Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
232cc320bd | ||
|
|
e7edc46daf | ||
|
|
6813ab4e65 | ||
|
|
fd714cbceb | ||
|
|
db6bd890d9 | ||
|
|
7a46c5ff31 | ||
|
|
98a9042c07 | ||
|
|
4170e18dea | ||
|
|
230ef2484d | ||
|
|
beba92aed4 | ||
|
|
cbb693e99e | ||
|
|
774e068436 | ||
|
|
86ba21029d | ||
|
|
316ac61875 | ||
|
|
d5d264d13b | ||
|
|
c71e1adc93 | ||
|
|
564d0ae974 | ||
|
|
9a48ec194e | ||
|
|
bb0a7f91cc | ||
|
|
73e54352cd | ||
|
|
64fa6fd9e5 | ||
|
|
2d3f92aeed | ||
|
|
9e9856bb45 | ||
|
|
890e6280df | ||
|
|
da7e4b3a09 | ||
|
|
747a7de168 | ||
|
|
bfa47b3663 | ||
|
|
0e7f14159a | ||
|
|
b755ce9528 | ||
|
|
f3cae55bd4 | ||
|
|
f64bd55bc6 | ||
|
|
4c8bb846ea | ||
|
|
bd14fb90fc | ||
|
|
9e5bce90f4 | ||
|
|
72c7d4c886 | ||
|
|
558b637b07 | ||
|
|
767341b279 | ||
|
|
c73916b4e7 | ||
|
|
0361ca1c39 | ||
|
|
cd4cd22928 | ||
|
|
e1a0cf6ca5 | ||
|
|
73bb9d5afb | ||
|
|
183df4c135 | ||
|
|
f2b238f50a | ||
|
|
09194aa613 | ||
|
|
e58327d4ed | ||
|
|
8414aa6e4b | ||
|
|
7d1d690eb7 | ||
|
|
47ad7ccb5f | ||
|
|
679c4183e7 | ||
|
|
8807c75c51 | ||
|
|
be9d8f7ce3 | ||
|
|
a7a43a1124 | ||
|
|
8b2862a1b8 | ||
|
|
1d4b5c201e | ||
|
|
f983145897 | ||
|
|
d369f542c5 | ||
|
|
6c8a44b056 | ||
|
|
ef18f93609 | ||
|
|
540afb1573 | ||
|
|
2d7a924275 | ||
|
|
702799290f | ||
|
|
f7d3d371f7 | ||
|
|
311d20eeb2 | ||
|
|
afa913f2ed | ||
|
|
f0554676dd | ||
|
|
3337b9a98f | ||
|
|
22fdb9594d | ||
|
|
93a0052219 | ||
|
|
5c852e26c2 | ||
|
|
7d2118cd97 | ||
|
|
5e3c178b9e | ||
|
|
35aa78dad9 | ||
|
|
7747f5a3fa | ||
|
|
a2f1e76fea | ||
|
|
cf515bc5ca | ||
|
|
97cbfa11b7 | ||
|
|
f2b76d8b3b | ||
|
|
e2a6d02570 | ||
|
|
1d78ffc04d | ||
|
|
42b9d42a8f | ||
|
|
7dbbe84086 | ||
|
|
e9b85f5acb | ||
|
|
cb3b0ab2bb | ||
|
|
de772bf1f9 | ||
|
|
91a9bae308 | ||
|
|
fe7c152c97 | ||
|
|
333c7ce1c9 | ||
|
|
ef2303bc5d | ||
|
|
6d2b4ab775 | ||
|
|
b3dedfedc0 | ||
|
|
2a3743ff84 | ||
|
|
a5afd83c7b | ||
|
|
e8d1bab914 | ||
|
|
de654de911 | ||
|
|
37c0f75499 | ||
|
|
5c5c1c80cf | ||
|
|
e91ee9f62a | ||
|
|
213b4eace8 | ||
|
|
f695c0c164 | ||
|
|
194b6eb9d8 | ||
|
|
2aba16e2c9 | ||
|
|
0b09082450 | ||
|
|
29aa972f18 | ||
|
|
06b814b627 | ||
|
|
8c0994e290 | ||
|
|
b1d251e950 | ||
|
|
63cdbef219 | ||
|
|
8a8f0ab3ec | ||
|
|
1ef0359731 | ||
|
|
38863d3025 | ||
|
|
44f4372ca3 | ||
|
|
46d3769a44 | ||
|
|
65b7d71bdf | ||
|
|
1d67e38f78 | ||
|
|
3697a1af4d | ||
|
|
26ff596983 | ||
|
|
b33db9c1ab | ||
|
|
867469e9b3 | ||
|
|
a4fc5c6975 | ||
|
|
e87ccbfa22 | ||
|
|
17c15a74a2 | ||
|
|
8bbdf2e7cb | ||
|
|
b66058e417 | ||
|
|
4fce0181ab | ||
|
|
ba9678bd61 | ||
|
|
74e577610a | ||
|
|
37ec1a978e | ||
|
|
27fa9969f3 | ||
|
|
4045ffea3c | ||
|
|
e9e067eebf | ||
|
|
93176c91f4 | ||
|
|
7ee5973400 | ||
|
|
043e62ab63 | ||
|
|
f91f665f3f | ||
|
|
f985f42e93 | ||
|
|
c77f5f6252 | ||
|
|
60cae87bfa | ||
|
|
eda33f7d11 | ||
|
|
d1cf445327 | ||
|
|
8e3dd11f81 | ||
|
|
80a4beace6 | ||
|
|
6dc821186e | ||
|
|
26ec0716b9 | ||
|
|
97af576f6a | ||
|
|
0e986df7e5 | ||
|
|
45011c0fad | ||
|
|
ca919dddd6 | ||
|
|
6eea5dd109 | ||
|
|
46ee2eeded | ||
|
|
3741186656 | ||
|
|
704db225d1 | ||
|
|
ce0e9594df | ||
|
|
835b7eb6f7 | ||
|
|
172ff846fd | ||
|
|
97fddc45d9 | ||
|
|
8a018ce3ba | ||
|
|
baaec9db87 | ||
|
|
5d5c964d06 | ||
|
|
502d3fb335 | ||
|
|
5654322f54 | ||
|
|
bea31fdcb0 | ||
|
|
529002c2b7 | ||
|
|
4367d74102 | ||
|
|
04e34b8ca7 | ||
|
|
5ad8e23eae | ||
|
|
2db4b57013 | ||
|
|
d678fe4bfa | ||
|
|
be7fb9d3df | ||
|
|
39755a294a | ||
|
|
a8dcea1422 | ||
|
|
2080458f0d | ||
|
|
3398426293 | ||
|
|
878ffafb51 | ||
|
|
2233751668 | ||
|
|
b86831356b | ||
|
|
453e826a0f | ||
|
|
55b1456d45 | ||
|
|
47c59afea0 | ||
|
|
41222792ed | ||
|
|
5659faf7f0 | ||
|
|
2e75d9c80a | ||
|
|
0fcf8838cc | ||
|
|
758aae8556 | ||
|
|
ffbbd968c2 | ||
|
|
0d0dd250ee | ||
|
|
e3aaedbc33 | ||
|
|
81e674ad36 | ||
|
|
f6f5405a2c | ||
|
|
551ff6a6fb | ||
|
|
d3e5092b43 | ||
|
|
3fe8cdece3 | ||
|
|
69f203a718 | ||
|
|
a97f978cad | ||
|
|
07a4553e6e | ||
|
|
e33798ff90 | ||
|
|
d9faff19a5 | ||
|
|
4f0ab4f226 | ||
|
|
05740e0f64 | ||
|
|
666dc65b8e | ||
|
|
76a1b3286b | ||
|
|
9d9d2a2a98 | ||
|
|
219c8b927d | ||
|
|
c616958557 | ||
|
|
453ab95e54 | ||
|
|
7fdab46729 | ||
|
|
798061506e | ||
|
|
0ad0d4ea11 | ||
|
|
f7b52d16f5 | ||
|
|
e24a29b146 | ||
|
|
ffb2640736 | ||
|
|
f9492691a6 | ||
|
|
1c0e6d76f0 | ||
|
|
88c04ce959 | ||
|
|
5ead23a8d4 | ||
|
|
d0ccb54aba | ||
|
|
aaad01105e | ||
|
|
6bdd433570 | ||
|
|
c767e5ebed | ||
|
|
4718efab9b | ||
|
|
145493388a | ||
|
|
16bd0d134e | ||
|
|
f58cbc2594 | ||
|
|
1e190e462a | ||
|
|
70da2b7b4d | ||
|
|
2297c58ab6 | ||
|
|
5e97e29f95 | ||
|
|
5037282b98 | ||
|
|
0b3685e529 | ||
|
|
2adb80729b | ||
|
|
c074c8d0ca | ||
|
|
2b62573b65 | ||
|
|
16fd12024e | ||
|
|
bf3466f3cb | ||
|
|
eebd2efcbf | ||
|
|
c573310c77 | ||
|
|
d6691fe9d8 | ||
|
|
275f071b12 | ||
|
|
ad8d550d73 | ||
|
|
fceeaf42ca | ||
|
|
30fdff17b5 | ||
|
|
6d53862142 | ||
|
|
1c27a0c1cf | ||
|
|
5ef753bfa8 | ||
|
|
52ce80f2b4 | ||
|
|
d8a790a13c | ||
|
|
20801263ec | ||
|
|
4cf52ea025 | ||
|
|
de132d39ec | ||
|
|
114c0ea85c | ||
|
|
51ef39592f | ||
|
|
eb3ca82fa0 | ||
|
|
a081dc7674 | ||
|
|
924fd82d7f | ||
|
|
2177fd59ef | ||
|
|
d81feb05d1 | ||
|
|
0a620514b7 | ||
|
|
e52232d85f | ||
|
|
4cdd81ec86 | ||
|
|
6e711ed739 | ||
|
|
8778787091 | ||
|
|
ce8bcf7932 | ||
|
|
abaef98fd8 | ||
|
|
ddc5e57d4d | ||
|
|
c723554d2e | ||
|
|
021f4a881c | ||
|
|
ada5e6ae68 | ||
|
|
8e7a8d8c97 | ||
|
|
9151f8b492 | ||
|
|
86cb865fdd | ||
|
|
38cb2601d7 | ||
|
|
94173c273a | ||
|
|
01449e486c | ||
|
|
8111b227c4 | ||
|
|
8bb471bccd | ||
|
|
5074b526d0 | ||
|
|
1608cd2d53 | ||
|
|
a123ef6fce | ||
|
|
23ec780a13 | ||
|
|
5569f96885 | ||
|
|
930be3d0e5 | ||
|
|
f84b1d0de9 | ||
|
|
8423325a6e | ||
|
|
97273655dc | ||
|
|
10acc04ba5 | ||
|
|
d20b6adfd2 | ||
|
|
a4c650316a | ||
|
|
28f57667f0 | ||
|
|
f53d2e3a46 | ||
|
|
7b76aa2078 | ||
|
|
d76a3b87c5 | ||
|
|
da6d384300 | ||
|
|
4c489d18a2 | ||
|
|
9785f14df8 | ||
|
|
d35b273dbf | ||
|
|
13c828f112 | ||
|
|
ea6ee8e899 | ||
|
|
1d3a21f6c8 | ||
|
|
3daa0b5e63 | ||
|
|
5426ef0b46 | ||
|
|
860a6a231d | ||
|
|
da7fc8dbb3 | ||
|
|
f03f4775fc | ||
|
|
0e39d62c9d | ||
|
|
d196e4a8df | ||
|
|
a59dadccc9 | ||
|
|
05db79ee35 | ||
|
|
d552803f56 | ||
|
|
d2a10413a1 | ||
|
|
ca8f5861fe | ||
|
|
7536744dcf | ||
|
|
8ba0385b3a | ||
|
|
9a5542100a | ||
|
|
b774563ec3 | ||
|
|
ca7aa69597 | ||
|
|
5aeabe39b5 | ||
|
|
5f79ff340d | ||
|
|
5a2b439773 | ||
|
|
cfbbcd420f | ||
|
|
59f765f7be | ||
|
|
528e39fcb3 | ||
|
|
2b16e69e90 | ||
|
|
09ebd1a557 | ||
|
|
edc2a28f1d | ||
|
|
7fe8580da5 | ||
|
|
7cc9c83ab8 | ||
|
|
0962292f92 | ||
|
|
b7f2487c4f | ||
|
|
db86647e3a | ||
|
|
7415627d95 | ||
|
|
fa6bae988e | ||
|
|
2c98bf0cc7 | ||
|
|
351313523c | ||
|
|
80ecbeddbb | ||
|
|
8222f803d5 | ||
|
|
d5b33671c2 | ||
|
|
e86749dfe2 | ||
|
|
ec5903ca19 | ||
|
|
b5dcb5964a | ||
|
|
8417f516e5 | ||
|
|
9532441ed4 | ||
|
|
630dfb9b55 | ||
|
|
f31dc791e4 | ||
|
|
ba881eb4cf | ||
|
|
ad5793e446 | ||
|
|
997d49b63f | ||
|
|
72fb6afae2 | ||
|
|
f9df806f15 | ||
|
|
01737ef1cc | ||
|
|
3321f36b51 | ||
|
|
64bdd620ac | ||
|
|
82f5984de1 | ||
|
|
b8bbbf3ea3 | ||
|
|
247b5205fb | ||
|
|
2b83089da8 | ||
|
|
7290431cb0 | ||
|
|
95a75daf9f | ||
|
|
80ed6b8c25 | ||
|
|
49d64f7f7e | ||
|
|
f09f38085e | ||
|
|
04a9822573 | ||
|
|
5848877734 | ||
|
|
93814cc85a | ||
|
|
4f30311971 | ||
|
|
cfe5134375 | ||
|
|
219d3c9f18 | ||
|
|
9110776a01 | ||
|
|
625c6951bb | ||
|
|
56235aee90 | ||
|
|
e14c80360d | ||
|
|
98d51d3d80 | ||
|
|
4f45c623a5 | ||
|
|
c96613a499 | ||
|
|
e1e01524e7 | ||
|
|
0926f95979 | ||
|
|
a4decaa188 | ||
|
|
27f7d3a658 | ||
|
|
0e6ff668eb | ||
|
|
fba3ed7b4d | ||
|
|
648130eec5 | ||
|
|
606a58bc6b | ||
|
|
09a645e455 | ||
|
|
d972a47c84 | ||
|
|
494c774303 | ||
|
|
28ac2fce61 | ||
|
|
5095e6f07b | ||
|
|
9a3b2abbab | ||
|
|
4e5b11b1d5 | ||
|
|
7eb2710e67 | ||
|
|
0a36db06ed | ||
|
|
e86f90fe8d | ||
|
|
953effcc43 | ||
|
|
a62e44c4e5 | ||
|
|
84a632787c | ||
|
|
16f0daab90 | ||
|
|
3149390b3b | ||
|
|
0185090cbb | ||
|
|
806f7dd15f | ||
|
|
013ebc617e | ||
|
|
63a60cdd75 | ||
|
|
4bcc71c68f | ||
|
|
7f1374e058 | ||
|
|
3935fd77ac | ||
|
|
9d0c8ae3dd | ||
|
|
4e7fd5b6d7 | ||
|
|
a4ded8c2b9 | ||
|
|
4a75e1e4b4 | ||
|
|
11b11e416b | ||
|
|
1f660c9e04 | ||
|
|
20ffce5c0d | ||
|
|
a7ef61279c | ||
|
|
5ee85dc263 | ||
|
|
93dc33687a | ||
|
|
932ab61c2d | ||
|
|
1d9b1f4aab | ||
|
|
7aed16ce4c | ||
|
|
9f4506bda5 | ||
|
|
fa6f9f4ae0 | ||
|
|
78ff5e270c | ||
|
|
6d1682a27e | ||
|
|
64768f093d | ||
|
|
a24db6c584 | ||
|
|
050a0ec5e4 | ||
|
|
0254e4b365 | ||
|
|
3ebe4ebb3d | ||
|
|
094baf8aa9 | ||
|
|
ff5ac51c54 | ||
|
|
9e130af9e7 | ||
|
|
bed7158212 | ||
|
|
398cbd7f2c | ||
|
|
5aa90b0478 | ||
|
|
86c936759b | ||
|
|
22bdc43023 | ||
|
|
ec2bc0baf6 | ||
|
|
5b860261a0 | ||
|
|
010e32d778 | ||
|
|
1097d29213 | ||
|
|
a6492b1ed6 | ||
|
|
59d2034cbb | ||
|
|
39ef3a701b | ||
|
|
7fdffc0340 | ||
|
|
f2bd680cc5 | ||
|
|
59f554b658 | ||
|
|
0ad38fe38f | ||
|
|
5c4db23da4 | ||
|
|
708a8b6543 | ||
|
|
d8e58e67c6 | ||
|
|
6c7874c883 | ||
|
|
15204a9b90 | ||
|
|
489d5239a5 | ||
|
|
f934ebd429 | ||
|
|
fccdd70524 | ||
|
|
5e40dda3bc | ||
|
|
fb8340acb2 | ||
|
|
20fbd66c90 | ||
|
|
b27ee8241a | ||
|
|
7806a9885a | ||
|
|
6e4889d340 | ||
|
|
679a8e0c24 | ||
|
|
6c3d8ec1de | ||
|
|
29078aaae9 | ||
|
|
8a45148070 | ||
|
|
df635579c4 | ||
|
|
788c7dbf48 | ||
|
|
99ecef89b8 | ||
|
|
51ca460f18 | ||
|
|
e236173417 | ||
|
|
15191ff80f | ||
|
|
efd2129187 | ||
|
|
73da4b9eed | ||
|
|
36ff37ba47 | ||
|
|
a33784c434 | ||
|
|
deb013cecb | ||
|
|
cb411637cc | ||
|
|
be89466367 | ||
|
|
111c7cf688 | ||
|
|
75e0387be2 | ||
|
|
c4e32fac1f | ||
|
|
038e83b647 | ||
|
|
82ef0529d8 | ||
|
|
6abfbbddd5 | ||
|
|
ad889a7240 | ||
|
|
e22ae9f826 | ||
|
|
d3e95d6b77 | ||
|
|
8db262c941 | ||
|
|
793eda986b | ||
|
|
1cd49cec39 | ||
|
|
10c1399474 | ||
|
|
4709e231b8 | ||
|
|
f8a14184c7 | ||
|
|
0155a31d1f | ||
|
|
8848c549a0 | ||
|
|
4919a005d3 | ||
|
|
dabe14889d | ||
|
|
6d1e711b2a | ||
|
|
e19087722f | ||
|
|
d3ac243cea | ||
|
|
348dadf7ae | ||
|
|
cba5ae81ed | ||
|
|
6d328c0a71 | ||
|
|
7a7066896e | ||
|
|
a2c0c10d2a | ||
|
|
c473d3c682 | ||
|
|
bedbdcaf13 | ||
|
|
87e6c0973a | ||
|
|
78876947a4 | ||
|
|
b59f58435c | ||
|
|
4adb83eaae | ||
|
|
4ac9828b0c | ||
|
|
77f6e0d4f8 | ||
|
|
835dbfe001 | ||
|
|
f5eb3fd086 | ||
|
|
da9630c561 | ||
|
|
a89faa72ea | ||
|
|
e042ce21f6 | ||
|
|
d4fef1b5f8 | ||
|
|
d5c4b66ec7 | ||
|
|
0009f7c8dc | ||
|
|
cd2e794d3f | ||
|
|
9bb862d025 | ||
|
|
91bb559bdf | ||
|
|
7fb4851eb9 | ||
|
|
6c2fa9086e | ||
|
|
0d61e0d717 | ||
|
|
d0585ca7bb | ||
|
|
14cda27e9f | ||
|
|
cf177bfea5 | ||
|
|
f84bbd4520 | ||
|
|
2bf8fb8c84 | ||
|
|
a553db4b82 | ||
|
|
121be5c6e8 | ||
|
|
e23e3db5b5 | ||
|
|
babaab20ea | ||
|
|
9d67c16ab9 | ||
|
|
9908031b0b | ||
|
|
6b3282150b | ||
|
|
58cfac9f67 | ||
|
|
340d11be38 | ||
|
|
62b15ecc12 | ||
|
|
6b9d392d0e | ||
|
|
9c68123ede | ||
|
|
7049b6478c | ||
|
|
0e6d34c0c9 | ||
|
|
a01fa11a26 | ||
|
|
4c71182c6b | ||
|
|
7e81081899 | ||
|
|
fb033a3719 | ||
|
|
a085b3b5f3 | ||
|
|
ec4146642d | ||
|
|
09bcc7aa52 | ||
|
|
8cc8a277a1 | ||
|
|
a5c56dde10 | ||
|
|
7f427b8001 | ||
|
|
33b12782e4 | ||
|
|
b2ff231c48 | ||
|
|
d921791c55 | ||
|
|
05d65c3f88 | ||
|
|
cf3298cd04 | ||
|
|
d789ca9299 | ||
|
|
aacfcba400 | ||
|
|
56d419e906 | ||
|
|
e4e0f472f9 | ||
|
|
2eadc7010a | ||
|
|
55cbb3480c | ||
|
|
fda038cd89 | ||
|
|
2f6f978cd5 | ||
|
|
ae19b8ebfd | ||
|
|
519d68ff6b | ||
|
|
90337995ff | ||
|
|
aa2cad1a66 | ||
|
|
4f6dc0748d | ||
|
|
6b8191121c | ||
|
|
9bc48a8867 | ||
|
|
ecc3ff4a5c | ||
|
|
71a2dc06d7 | ||
|
|
f7d9603c0c | ||
|
|
256a26d12a | ||
|
|
3736d1ce45 | ||
|
|
672269e9d6 | ||
|
|
f200ac6287 | ||
|
|
1447a66515 | ||
|
|
d9796cd25c | ||
|
|
ee79855536 | ||
|
|
33ada25ba8 | ||
|
|
da90caedf0 | ||
|
|
6a7cb669ac | ||
|
|
8ae74f67df | ||
|
|
fc34b86470 | ||
|
|
b87c89ad16 | ||
|
|
4e74e66903 | ||
|
|
ce8b369419 | ||
|
|
b5f4a91002 | ||
|
|
db4896577c | ||
|
|
119f6ff2e6 | ||
|
|
80f8f71a96 | ||
|
|
7e0ba4aa32 | ||
|
|
da8dbc8ffe | ||
|
|
27e3f8ee29 | ||
|
|
4311c96a44 | ||
|
|
a236957538 | ||
|
|
0806fd651a | ||
|
|
bf579a86a0 | ||
|
|
12af420d7e | ||
|
|
88016c17e4 | ||
|
|
0df6e1e2c7 | ||
|
|
399a483708 | ||
|
|
8b923c123a | ||
|
|
b378f8d310 | ||
|
|
25875b4cd8 | ||
|
|
04bd91b2f3 | ||
|
|
9e2f56b0b7 | ||
|
|
5c315b4503 | ||
|
|
817358f1bb | ||
|
|
3debf005a8 | ||
|
|
087955e927 | ||
|
|
e33d398c33 | ||
|
|
9fc674feb4 | ||
|
|
0c875774ce | ||
|
|
3027283756 | ||
|
|
161cb32078 | ||
|
|
84bbf7f420 | ||
|
|
dad3e96719 | ||
|
|
984e52acbc | ||
|
|
d022dba14a | ||
|
|
bf98ebe33e | ||
|
|
7d704bf86b | ||
|
|
aabb90293d | ||
|
|
6b8beabad0 | ||
|
|
438fa637df | ||
|
|
30b28b7f7b | ||
|
|
4b80bc93b0 | ||
|
|
54862be3ff | ||
|
|
2e78f2c267 | ||
|
|
a03931daab | ||
|
|
8df9c483f3 | ||
|
|
6ed1c9e905 | ||
|
|
f21ce3e8ee | ||
|
|
7c1e0d2132 | ||
|
|
5733c71c50 | ||
|
|
4bf7619d32 | ||
|
|
659babc6b3 | ||
|
|
38a2f82f78 | ||
|
|
7456cdeb42 | ||
|
|
0eac90b596 | ||
|
|
7f895f03f5 | ||
|
|
393ac5a7c7 | ||
|
|
d08458a03c | ||
|
|
d1718369a1 | ||
|
|
57af7e8d1e | ||
|
|
af3fe206d6 | ||
|
|
29f6d50c49 | ||
|
|
896edfe072 | ||
|
|
2010bf55b7 | ||
|
|
ccd000cc16 | ||
|
|
de05120e69 | ||
|
|
0ada762971 | ||
|
|
d8a669c85a | ||
|
|
db240359f7 | ||
|
|
87f1b7564c | ||
|
|
807504fa16 | ||
|
|
93e566d7e0 | ||
|
|
c02c69a8d6 | ||
|
|
6193f4e062 | ||
|
|
364e3229b9 | ||
|
|
98d6d25c74 | ||
|
|
67bf952c5a | ||
|
|
0acc461cb1 | ||
|
|
cd82f79d35 | ||
|
|
e035e29595 | ||
|
|
b89e94ee86 | ||
|
|
fc41b72bb6 | ||
|
|
0086f76a90 | ||
|
|
92faf5c5f9 | ||
|
|
3eeec8d438 | ||
|
|
bf10de82df | ||
|
|
4ce71bce2d | ||
|
|
e9c526b218 | ||
|
|
2675ffb128 | ||
|
|
885f357c59 | ||
|
|
de41f63fa4 | ||
|
|
a4807b18bc | ||
|
|
b42625d824 | ||
|
|
71cf358ee3 | ||
|
|
5ea61abfe1 | ||
|
|
4a3c273072 | ||
|
|
0292c979ab | ||
|
|
a78258efdf | ||
|
|
bee6c0e26e | ||
|
|
6e492e41d1 | ||
|
|
f943ea7d5d | ||
|
|
ed098390cb | ||
|
|
3ed3e4f5d7 | ||
|
|
6117afe0be | ||
|
|
f5dcd4a25f | ||
|
|
05f1a23c94 | ||
|
|
621d675938 | ||
|
|
4f25c1c60e | ||
|
|
fecaeda382 | ||
|
|
3df85ca784 | ||
|
|
2ab202a03d | ||
|
|
f1632376e7 | ||
|
|
073efeeacb | ||
|
|
e38f4219c5 | ||
|
|
30b6f38704 | ||
|
|
04e4bab313 | ||
|
|
19253dbbb1 | ||
|
|
dddf7951ef | ||
|
|
6c5a91735a | ||
|
|
b13681df32 | ||
|
|
a21234cd54 | ||
|
|
d317835535 | ||
|
|
20cb9425cc | ||
|
|
4f4cebadc7 | ||
|
|
74f35c88ad | ||
|
|
c7a6e32c96 | ||
|
|
99e71badbf | ||
|
|
e894f360a5 | ||
|
|
63ad6bc325 | ||
|
|
4fc5f9fe9f | ||
|
|
66ac7c195c | ||
|
|
80e6e56a82 | ||
|
|
0471b10de5 | ||
|
|
2dfc15c67d | ||
|
|
d0f6804283 | ||
|
|
ef7f7375e7 | ||
|
|
7f6c86daae | ||
|
|
d2d72c76e0 | ||
|
|
ec4603e55d | ||
|
|
f511cc188a | ||
|
|
7de7e65dbc | ||
|
|
98f00b510f | ||
|
|
e47e51275a | ||
|
|
916bebadef | ||
|
|
abca69b476 | ||
|
|
71aa3a59d9 | ||
|
|
19be380b53 | ||
|
|
574a22de6c | ||
|
|
8675ca561d | ||
|
|
2b15831672 | ||
|
|
1dd554ad71 | ||
|
|
3fd4921ea3 | ||
|
|
a03192a39b | ||
|
|
6d9707c784 | ||
|
|
d23cd2e507 | ||
|
|
25448798b0 | ||
|
|
d1cb60bdee | ||
|
|
e0b72ba049 | ||
|
|
4d01cbfb62 | ||
|
|
8d4427a8bc | ||
|
|
8bca545cab | ||
|
|
9c98cf8bc1 | ||
|
|
8acd926636 | ||
|
|
12f7ead55e | ||
|
|
02d21c2833 | ||
|
|
b23cac19ab | ||
|
|
446a4f6272 | ||
|
|
42730bcf1c | ||
|
|
214eeccb18 | ||
|
|
2570712a29 | ||
|
|
6a7d72c030 | ||
|
|
e7d65be90a | ||
|
|
baf91f08a1 | ||
|
|
255bd6881a | ||
|
|
886d9cd5eb | ||
|
|
c9fdd4bee2 | ||
|
|
d1592b01c3 | ||
|
|
043b63d8d8 | ||
|
|
6a49bd6d8e | ||
|
|
65ffde9e4b | ||
|
|
c841f26256 | ||
|
|
4cd56b3b99 | ||
|
|
2d73b04f7d | ||
|
|
36d87eb8e9 | ||
|
|
1ba5dd4c72 | ||
|
|
b4d9b6efaf | ||
|
|
4ae02ef1b9 | ||
|
|
88fbc044b3 | ||
|
|
8942c02f28 | ||
|
|
add56c8b81 | ||
|
|
37ff876bc6 | ||
|
|
4287f76ed4 | ||
|
|
64e18131c1 | ||
|
|
fabf26cc21 | ||
|
|
94e4f8d116 | ||
|
|
6734287789 | ||
|
|
13e5b72cdb | ||
|
|
8cae101c04 | ||
|
|
d1743555d4 | ||
|
|
b463749594 | ||
|
|
4ef5a58b36 | ||
|
|
1bd90d0701 | ||
|
|
127d6d0576 | ||
|
|
9db478fd2e | ||
|
|
1cf2d1aad5 | ||
|
|
01b5118a08 | ||
|
|
5c71d25872 | ||
|
|
ef8b9eae93 | ||
|
|
dfa2ac6807 | ||
|
|
f05cff478f | ||
|
|
cb71386ed9 | ||
|
|
7fbbf23e5a | ||
|
|
5ace7479ad | ||
|
|
5040623a12 | ||
|
|
ff7f0a9dcd | ||
|
|
ca552cf83b | ||
|
|
2e78ed685f | ||
|
|
01df17f1e7 | ||
|
|
f87ede501c | ||
|
|
bb79af7721 | ||
|
|
a66e202f02 | ||
|
|
29db7047a3 | ||
|
|
6ef7a30b19 | ||
|
|
1f016262cd | ||
|
|
80fef50b90 | ||
|
|
704578c9c2 | ||
|
|
cfc1a54ee5 | ||
|
|
f31473c4cf | ||
|
|
09dbd12638 | ||
|
|
b37a39588e | ||
|
|
0b498d25f6 | ||
|
|
b25215e31b | ||
|
|
f5b0c30633 | ||
|
|
862bafc63a | ||
|
|
c3c6fda9d5 | ||
|
|
efdc428d5d | ||
|
|
7595b1d8d4 | ||
|
|
39bcfab37c | ||
|
|
ae40555558 | ||
|
|
9c30b17b5a | ||
|
|
aded4b4199 | ||
|
|
eb616bff7f | ||
|
|
8cf9595d35 | ||
|
|
5c23ec73cb | ||
|
|
8d7994cd82 | ||
|
|
fb77a758ff | ||
|
|
3b6e2bdb7b | ||
|
|
1898b82dc4 | ||
|
|
290011166f | ||
|
|
c5c819afca | ||
|
|
c2687f9064 | ||
|
|
548e94d3fc | ||
|
|
ae88a99c84 | ||
|
|
0d3aaabd2c | ||
|
|
f1c452754f | ||
|
|
b9d67296ef | ||
|
|
483e82e14b | ||
|
|
884d4ad9df | ||
|
|
4f6d01d2ea | ||
|
|
2b511d2f57 | ||
|
|
1eed341951 | ||
|
|
3c17cd655e | ||
|
|
fb0ccc9260 | ||
|
|
aa679a7359 | ||
|
|
054fc4a614 | ||
|
|
10b5e3e576 | ||
|
|
e3c241e613 | ||
|
|
a0c0d9c98a | ||
|
|
322b33197c | ||
|
|
7f27c80a6a | ||
|
|
9a23ede4fd | ||
|
|
9328dc27f3 | ||
|
|
98643b90f8 | ||
|
|
aa419155f6 | ||
|
|
b75ba5ea46 | ||
|
|
8dfcf2b7d3 | ||
|
|
8774a7b2dd | ||
|
|
9012fea2f6 | ||
|
|
a52e406c0d | ||
|
|
45476a208e | ||
|
|
4ca5fef0de | ||
|
|
42bb91c2e6 | ||
|
|
1ecec49885 | ||
|
|
7fa2f20e8c | ||
|
|
d9ad6fb8c8 | ||
|
|
aa611e49fd | ||
|
|
0359a458e4 | ||
|
|
0377d6952b | ||
|
|
ec242c1ba7 | ||
|
|
4a0171d26a | ||
|
|
8955690d76 | ||
|
|
25cb3a15e7 | ||
|
|
6b5525b8d2 | ||
|
|
0c75dd3865 | ||
|
|
4d204d2c25 | ||
|
|
75eaa1bf5b | ||
|
|
b44d188912 | ||
|
|
a5d2ec0df8 | ||
|
|
b844f70a3c | ||
|
|
5fe85c07b1 | ||
|
|
5ca410ae99 | ||
|
|
2d90bcff3c | ||
|
|
c2a24b7b4c | ||
|
|
b49276ef47 | ||
|
|
eb2879ca22 | ||
|
|
5702ea236c | ||
|
|
b3f27c0075 | ||
|
|
50d4c2e0ac | ||
|
|
6c1ecb4d16 | ||
|
|
f27a122787 | ||
|
|
55f88b46cf | ||
|
|
15a81707b4 | ||
|
|
a6d79b26e4 | ||
|
|
2db1001a07 | ||
|
|
d94119dada | ||
|
|
9aa8791920 | ||
|
|
ff7e441c82 | ||
|
|
2eff03fa1f | ||
|
|
5c0d86373e | ||
|
|
8a8017c536 | ||
|
|
3198d2d1e5 | ||
|
|
dd619e85ff | ||
|
|
536b2ad9d7 | ||
|
|
7fc15b70ec | ||
|
|
428e315d2a | ||
|
|
91b5ec1aba | ||
|
|
a883b1b9a9 | ||
|
|
47582c0bb3 | ||
|
|
0daed04c07 | ||
|
|
09f5a64ce0 | ||
|
|
f3eec33bec | ||
|
|
1aa8b6cab2 | ||
|
|
0f5598e59b | ||
|
|
5e8ae7498a | ||
|
|
7bbf1c7db2 | ||
|
|
f35555964d | ||
|
|
d25f386bb5 | ||
|
|
a366522c8d | ||
|
|
9a39bb4e78 | ||
|
|
ccfb33c294 | ||
|
|
0cb58311c3 | ||
|
|
3b23ab952b | ||
|
|
069c39fc12 | ||
|
|
3f2a62b5e2 | ||
|
|
632fd36205 | ||
|
|
f212ca60c8 | ||
|
|
1555984785 | ||
|
|
066bac0607 | ||
|
|
02650c7f25 | ||
|
|
936d861df5 | ||
|
|
f0d32f2c01 | ||
|
|
7e36188519 | ||
|
|
97489f8bf9 | ||
|
|
5ac8424f93 | ||
|
|
c9a4bfba1a | ||
|
|
bd31e8d37e | ||
|
|
cac3d07abb | ||
|
|
335d165db6 | ||
|
|
69a472c4ea | ||
|
|
ce21557d64 | ||
|
|
0a2c2e9a07 | ||
|
|
b3a31d8823 | ||
|
|
4308d37c84 | ||
|
|
cc54efd88b | ||
|
|
cae98ac0ab | ||
|
|
e7e068ebb5 | ||
|
|
43e1b57c3f | ||
|
|
5561d66082 | ||
|
|
d614135ebb | ||
|
|
3ef3f570fb | ||
|
|
c73d597d87 | ||
|
|
e83fa0dd04 | ||
|
|
73ad453748 | ||
|
|
8408a56e55 | ||
|
|
e689c305d2 | ||
|
|
12f7e2d9bf | ||
|
|
5b280057b8 | ||
|
|
fd49ef8de6 | ||
|
|
fd4d2067a9 | ||
|
|
e1a1b325bc | ||
|
|
43586ed9a1 | ||
|
|
ba28169356 | ||
|
|
b6b5a79833 | ||
|
|
165bcc1e38 | ||
|
|
48ab706691 | ||
|
|
fe2da35a45 | ||
|
|
5933e64de1 | ||
|
|
bfa0ae16b0 | ||
|
|
fd41a16f84 | ||
|
|
491e24c90a | ||
|
|
f7c222e42e | ||
|
|
2a699e1de9 | ||
|
|
e17732b365 | ||
|
|
e50ea377ef | ||
|
|
c68b023d3f | ||
|
|
6fe743f3a9 | ||
|
|
03c1776b43 | ||
|
|
78eaac6534 | ||
|
|
8f56814ffb | ||
|
|
6f890a3edd | ||
|
|
6f031993ba | ||
|
|
41f1c74ae2 | ||
|
|
e18904bff5 | ||
|
|
5c715021c1 | ||
|
|
43b30a80c1 | ||
|
|
ed72aa1307 | ||
|
|
9248e5a572 | ||
|
|
9135a5d048 | ||
|
|
f2ac17845b | ||
|
|
d0147aa50f | ||
|
|
9d20a5c97b | ||
|
|
5791765526 | ||
|
|
b179eaea21 | ||
|
|
b252715f53 | ||
|
|
f2e89e6b16 | ||
|
|
8367e79279 | ||
|
|
5169785c91 | ||
|
|
ac6e716ebd | ||
|
|
e2c6cc6c6d | ||
|
|
7be18df6ea | ||
|
|
472e502218 | ||
|
|
7b16fe3792 | ||
|
|
47f81f1ad6 | ||
|
|
cf34fe5cc3 | ||
|
|
7396212c89 | ||
|
|
e876617c82 | ||
|
|
42951d05a5 | ||
|
|
45cac72f7a | ||
|
|
922d568e12 | ||
|
|
a5e0a05932 | ||
|
|
8c516df87b | ||
|
|
f537c48f93 | ||
|
|
4b93c5d194 | ||
|
|
1fc768fb32 | ||
|
|
2efb18f677 | ||
|
|
d6f9383528 | ||
|
|
02b0c8dd94 | ||
|
|
f018e870dc | ||
|
|
53e06f358a | ||
|
|
9032163c5a | ||
|
|
a45febc065 | ||
|
|
75f5afc0da | ||
|
|
a467deede6 | ||
|
|
763074bb2d | ||
|
|
f857ee159e | ||
|
|
2aaf14b558 | ||
|
|
01af855450 | ||
|
|
d3baf2b9eb | ||
|
|
51cf4a5749 | ||
|
|
0409c5a482 | ||
|
|
56e3f7da7d | ||
|
|
a881e58cd6 | ||
|
|
4da3aedacb | ||
|
|
0091f3a9ce | ||
|
|
268d435ce0 | ||
|
|
b309e80e41 | ||
|
|
2057433f48 | ||
|
|
d3c8f295c2 | ||
|
|
080614098d | ||
|
|
8eff3a25f9 | ||
|
|
28fe602a9b | ||
|
|
ca803d99fe | ||
|
|
37fe0dbed2 | ||
|
|
7a7cce2538 | ||
|
|
657b390193 | ||
|
|
fe83334ed9 | ||
|
|
55355c4165 | ||
|
|
878b8c7678 | ||
|
|
f25611d768 | ||
|
|
90b5e47fa5 | ||
|
|
6b0f607f4b | ||
|
|
5e54219be9 | ||
|
|
957d83f069 | ||
|
|
c8a5e31d65 | ||
|
|
347ed154b8 | ||
|
|
51444c7f18 | ||
|
|
6d85d379ba | ||
|
|
a86caaa11d | ||
|
|
532c32a741 | ||
|
|
45db0abb59 | ||
|
|
110ccfc88f | ||
|
|
c72f853e09 | ||
|
|
a6100b7e46 | ||
|
|
fb0afbf3b0 | ||
|
|
624731cb80 | ||
|
|
641eb3e2cf | ||
|
|
85d8133f4a | ||
|
|
0edf65855a | ||
|
|
0eaf44eb31 | ||
|
|
bc381fc053 | ||
|
|
0d1174cb81 | ||
|
|
3710f33e14 | ||
|
|
5ea9df1824 | ||
|
|
a826877ee3 | ||
|
|
ea92f5f1ff | ||
|
|
46fd9d5e80 | ||
|
|
b41a0ea197 | ||
|
|
ed2778f785 | ||
|
|
bcb33d75d0 | ||
|
|
ae1ae58dd7 | ||
|
|
5f157affdd | ||
|
|
44551124e2 | ||
|
|
9bc5d9489d | ||
|
|
d04d947cb7 | ||
|
|
b469277046 | ||
|
|
809e7d5390 | ||
|
|
4cdb5f7b81 | ||
|
|
2d9f2c7e72 | ||
|
|
40ac52a862 | ||
|
|
b2b7f14432 | ||
|
|
e65db33d77 | ||
|
|
4c8c8f48f1 | ||
|
|
702d95503b | ||
|
|
01b8a6de94 | ||
|
|
a193feec06 | ||
|
|
b7fe5d438f | ||
|
|
af15273f71 | ||
|
|
aef3a4d21d | ||
|
|
239b5f547a | ||
|
|
d1d4ca65b2 | ||
|
|
bf774fc29b | ||
|
|
e6c70c19d0 | ||
|
|
383e28e6e7 | ||
|
|
5e7adf5b3f | ||
|
|
fbe206f843 | ||
|
|
f7273bc4ee | ||
|
|
cdc6086308 | ||
|
|
eaf0861f20 | ||
|
|
88f677e891 | ||
|
|
4ed968b79c | ||
|
|
660929519c | ||
|
|
f809e478f4 | ||
|
|
4bf932a4d7 | ||
|
|
9898b4504f | ||
|
|
7a18578706 | ||
|
|
54a6d58c2e | ||
|
|
7e16e3e220 | ||
|
|
f5f11af73f | ||
|
|
f6e8f02fd2 | ||
|
|
f1140e5c89 | ||
|
|
2f9cef38a1 | ||
|
|
d3aa5e638d | ||
|
|
e488996fd0 | ||
|
|
1b56b88132 | ||
|
|
c735d0da0e | ||
|
|
b40346e1ea | ||
|
|
56c2894c80 | ||
|
|
c4251912dd | ||
|
|
42e1338ffe | ||
|
|
1063908dd3 | ||
|
|
70f93da5dd | ||
|
|
a939c30256 | ||
|
|
e0b86782e9 | ||
|
|
c62859e38b | ||
|
|
3bac504fc3 | ||
|
|
09b4971698 | ||
|
|
c8cf8f3ee1 | ||
|
|
9b28be14cd | ||
|
|
8aa8c15fb8 | ||
|
|
3fe8b1e732 | ||
|
|
cad59b045b | ||
|
|
9fa42680fe | ||
|
|
73342e1fcf | ||
|
|
051be61452 | ||
|
|
1101d4b66a | ||
|
|
b216785071 | ||
|
|
d31d6e61d8 | ||
|
|
60545e6722 | ||
|
|
5a50d293b9 | ||
|
|
d9f3233d5f | ||
|
|
5a5401dce3 | ||
|
|
b31b322e77 | ||
|
|
26f025bc96 | ||
|
|
e977649f29 | ||
|
|
c748dea537 | ||
|
|
ec098d4833 | ||
|
|
823d8a64e1 | ||
|
|
b7695f9408 | ||
|
|
bab7b8029b | ||
|
|
617046fc0e | ||
|
|
0612c2eab9 | ||
|
|
884d03f7f1 | ||
|
|
20e49e975f | ||
|
|
467172f437 | ||
|
|
122ec8c9be | ||
|
|
05c527b681 | ||
|
|
de86167a7b | ||
|
|
927f355001 | ||
|
|
41bc8f14a2 | ||
|
|
aa17d2bdf3 | ||
|
|
754d6cfea3 | ||
|
|
f55ed9ea09 | ||
|
|
52c993043c | ||
|
|
402b4b6c70 | ||
|
|
f45970a0d5 | ||
|
|
2b2b632cd6 | ||
|
|
79b701d347 | ||
|
|
e1de0e3408 | ||
|
|
07bf155295 | ||
|
|
6ecd831cae | ||
|
|
cb47f877a5 | ||
|
|
738296e8e9 | ||
|
|
5ef7328fe3 | ||
|
|
5f826a2147 | ||
|
|
94a38cd97d | ||
|
|
ab08858b45 | ||
|
|
32a5c52105 | ||
|
|
57d57e54a1 | ||
|
|
5dbbf50f62 | ||
|
|
f8a6e4dce7 | ||
|
|
4a831f3dd2 | ||
|
|
2212c10f3a | ||
|
|
3042183825 | ||
|
|
4004c657b9 | ||
|
|
78aa615b4d | ||
|
|
75771d10d4 | ||
|
|
4f509d9b67 | ||
|
|
aa4bd66f11 | ||
|
|
c29dd72174 | ||
|
|
245fe6e3df | ||
|
|
562a3f482e | ||
|
|
d6765847df | ||
|
|
6562b7a4bc | ||
|
|
b384ac6943 | ||
|
|
722d6e8ffb | ||
|
|
a625943fc3 | ||
|
|
2de0c9cb1a | ||
|
|
035fcad3d4 | ||
|
|
e54a87f91b | ||
|
|
42e1906d9c | ||
|
|
85f4bc7717 | ||
|
|
2166e9a0ff | ||
|
|
e2d5451ffb | ||
|
|
0a3e51a74c | ||
|
|
98420754a9 | ||
|
|
621bc3a251 | ||
|
|
7598a9d2fe | ||
|
|
e87d8f9543 | ||
|
|
d2fc7c8688 | ||
|
|
1ef9113ff0 | ||
|
|
63bb09553a | ||
|
|
28985c8bcf | ||
|
|
b048fcd7c1 | ||
|
|
45d9ddc79f | ||
|
|
aea1b0e293 | ||
|
|
c897cc0cc9 | ||
|
|
6d70d912a1 | ||
|
|
4abc7416f6 | ||
|
|
fdfccf0466 | ||
|
|
429f119dbb | ||
|
|
7216363d2e | ||
|
|
2c43138043 | ||
|
|
1e80e3ae65 | ||
|
|
bf9116c65a | ||
|
|
79e25ac300 | ||
|
|
6c502c4c9c | ||
|
|
c6acfa624e | ||
|
|
7a8c74fee8 | ||
|
|
16a1f9b682 | ||
|
|
61d027db2a | ||
|
|
711b626a8b | ||
|
|
bd15650724 | ||
|
|
004a6d8868 | ||
|
|
30ec4e7524 | ||
|
|
6f660f7915 | ||
|
|
6e8d51af02 | ||
|
|
35e519179a | ||
|
|
9babf34a0c | ||
|
|
73b8868046 | ||
|
|
e372e7dc63 | ||
|
|
f8b8ecc0c3 | ||
|
|
ca53bf9097 | ||
|
|
e90b52eb8d | ||
|
|
be1e7d33d5 | ||
|
|
967d887503 | ||
|
|
e01df1c602 | ||
|
|
ac25502308 | ||
|
|
80ef0b020e | ||
|
|
8e044be7c2 | ||
|
|
65512193cc | ||
|
|
a89c290f62 | ||
|
|
df38fe4bf6 | ||
|
|
6b8f27264b | ||
|
|
be1231fef4 | ||
|
|
ca4e4fa964 | ||
|
|
b7dca7fb4e | ||
|
|
e60af00ec4 | ||
|
|
8ce8801789 | ||
|
|
26804c0557 | ||
|
|
1511644541 | ||
|
|
96b3295307 | ||
|
|
a08d780bef | ||
|
|
77e4adb556 | ||
|
|
5f599dcaf5 | ||
|
|
0073f10b62 | ||
|
|
2b7732bc2f | ||
|
|
deec7a2658 | ||
|
|
7c3197d9b0 | ||
|
|
8458f04a6b | ||
|
|
829c7953d5 | ||
|
|
80546d0451 | ||
|
|
9e07b310d1 | ||
|
|
323e07df46 | ||
|
|
182b638f03 | ||
|
|
de3d3b48f7 | ||
|
|
a8b0db91e8 | ||
|
|
b4be1472c0 | ||
|
|
06a13681ae | ||
|
|
50e1650344 | ||
|
|
23003c4d55 | ||
|
|
9b6d822b3e | ||
|
|
9f7deff512 | ||
|
|
6e1bfaffd7 | ||
|
|
9681ac3fb9 | ||
|
|
9d9ea4e633 | ||
|
|
b2a114a808 | ||
|
|
b4d1b628be | ||
|
|
f4720ddb2c | ||
|
|
86a522ef22 | ||
|
|
d9ba8d3671 | ||
|
|
3058f280d9 | ||
|
|
9eea11662c | ||
|
|
5405a5adc3 | ||
|
|
5ff12a5d2d | ||
|
|
b8526edd5e | ||
|
|
b4ff9ba220 | ||
|
|
89d42b5958 | ||
|
|
e323fa7a8c | ||
|
|
c7eec94d95 | ||
|
|
7d7496e10b | ||
|
|
14535cc400 | ||
|
|
a7acc81490 | ||
|
|
593a7b623c | ||
|
|
6546db7648 | ||
|
|
761a999ebc | ||
|
|
7982ab52a7 | ||
|
|
b264cd6c4a | ||
|
|
1ec0ded953 | ||
|
|
9f82e98f28 | ||
|
|
e4f475ee59 | ||
|
|
adee59c795 | ||
|
|
1feec642da | ||
|
|
0bb4c20e02 | ||
|
|
1b38791d94 | ||
|
|
b58eba0d99 | ||
|
|
7fa666b0a3 | ||
|
|
d8d6f9cb51 | ||
|
|
6028b5b18f | ||
|
|
de18d5521e | ||
|
|
d2e203c1ce | ||
|
|
57b931b06a | ||
|
|
50ae04e6b7 | ||
|
|
3e23b3653b | ||
|
|
023b2ce126 | ||
|
|
89348d7fda | ||
|
|
cd8537e76f | ||
|
|
ad9a691e0a | ||
|
|
b6cf4964df | ||
|
|
82f24d62d4 | ||
|
|
c839ca456f | ||
|
|
3cab915fd2 | ||
|
|
83718c6165 | ||
|
|
d7e1a526f6 | ||
|
|
b672070ba2 | ||
|
|
a58edeb96f | ||
|
|
c0c692fa22 | ||
|
|
fc32410e5b | ||
|
|
755772e12d | ||
|
|
97b37474f9 | ||
|
|
3f6c418dc6 | ||
|
|
0e4d5cb67b | ||
|
|
ccaca48140 | ||
|
|
0d77c96bda | ||
|
|
76d40ec408 | ||
|
|
ed251d9f82 | ||
|
|
43491cb7ed | ||
|
|
f2d1fbdfa5 | ||
|
|
9c51b48754 | ||
|
|
fa240a37db | ||
|
|
113fcac476 | ||
|
|
31296e6cdc | ||
|
|
8260184abc | ||
|
|
f71957bcec | ||
|
|
78564e8c54 | ||
|
|
2e04dc908c | ||
|
|
255777a4a9 | ||
|
|
f2a3d23798 | ||
|
|
fe80f4b830 | ||
|
|
cb9406c2ca | ||
|
|
883b8467b5 | ||
|
|
65f8fae67a | ||
|
|
113681fcc4 | ||
|
|
b3fc3607f0 | ||
|
|
31f4f5a4e5 | ||
|
|
2394492798 | ||
|
|
81a65fe1bc | ||
|
|
5bfee9875c | ||
|
|
90baf06011 | ||
|
|
e5ca4b22d5 | ||
|
|
4e9343c487 | ||
|
|
8e6862f7ca | ||
|
|
3cac1080cc | ||
|
|
6b67c1cf39 | ||
|
|
7c32d49ec6 | ||
|
|
3ae55d1da3 | ||
|
|
2b50a3cb4a | ||
|
|
f9863f31fd | ||
|
|
c33e38eef2 | ||
|
|
910f9f00bd | ||
|
|
ae29d132ed | ||
|
|
d3da20ab27 | ||
|
|
6d21255678 | ||
|
|
bdf6904c1a | ||
|
|
f993ff1ab8 | ||
|
|
fc3c91b738 | ||
|
|
b83629c4d5 | ||
|
|
45f85a5f86 | ||
|
|
0552d23b77 | ||
|
|
bd6a80505b | ||
|
|
b6c9169a87 | ||
|
|
886e2e57dc | ||
|
|
21d15d3151 | ||
|
|
40b7783c77 | ||
|
|
a8e12f94e9 | ||
|
|
a8c6253fc7 | ||
|
|
fc0bd2cda5 | ||
|
|
483b33acd1 | ||
|
|
4cb4e7c2c2 | ||
|
|
6458354265 | ||
|
|
41199e5eca | ||
|
|
79dda448d7 | ||
|
|
0228ba1fb9 | ||
|
|
f56b31a5a5 | ||
|
|
e201408d61 | ||
|
|
e89890d54a | ||
|
|
f3c771db1c | ||
|
|
d8ca29dd52 | ||
|
|
1649c32325 | ||
|
|
741818ee67 | ||
|
|
9d987280c9 | ||
|
|
0e78db3b8c | ||
|
|
e19ff4c958 | ||
|
|
146e59fe56 | ||
|
|
5f091411c3 | ||
|
|
7fa4cd33f0 | ||
|
|
34bfafc7a7 | ||
|
|
38bcb9bc09 | ||
|
|
d52ad2ea77 | ||
|
|
c881f287ad | ||
|
|
a8e9a2fe92 | ||
|
|
898a72d078 | ||
|
|
bc0408b962 | ||
|
|
a4e30a851b | ||
|
|
8daef5aa23 | ||
|
|
595de3fccb | ||
|
|
7153e1dd05 | ||
|
|
f1f9ce5351 | ||
|
|
3d2084ab93 | ||
|
|
83e29b1ccd | ||
|
|
dd06e768d3 | ||
|
|
04b4a5e0c3 | ||
|
|
9ef69c91e4 | ||
|
|
c762770031 | ||
|
|
97009c8f0a | ||
|
|
14460d397a | ||
|
|
7f722623ca | ||
|
|
0d0fa1e670 | ||
|
|
12e79a1661 | ||
|
|
627d7b5269 | ||
|
|
4d328cad54 | ||
|
|
a0e7d6a781 | ||
|
|
d423ae90d8 | ||
|
|
8a74e06161 | ||
|
|
d57f0e6460 | ||
|
|
33dfb9a9cc | ||
|
|
48d1782e71 | ||
|
|
15ca665c21 | ||
|
|
8e6525e6dd | ||
|
|
5d1e51da9c | ||
|
|
224a60fb23 | ||
|
|
6e73e4b68e | ||
|
|
3ee28c3b6d | ||
|
|
729c052f64 | ||
|
|
84a44f93a7 | ||
|
|
a68d6239dc | ||
|
|
76440e703e | ||
|
|
bc36e949e8 | ||
|
|
ed33400a49 | ||
|
|
74dd01a8db | ||
|
|
7b567c77e9 | ||
|
|
2b883c8c41 | ||
|
|
49bca7f16c | ||
|
|
8b98fe1bf4 | ||
|
|
a1808ae019 | ||
|
|
4e4fbafbe0 | ||
|
|
4bbe5abf81 | ||
|
|
cadf52bb0a | ||
|
|
26d36f994f | ||
|
|
f7fa9ab055 | ||
|
|
0aaff740e8 | ||
|
|
ded5f5a4c6 | ||
|
|
4a92422f8b | ||
|
|
dbe2590f6e | ||
|
|
5eb74ba3f7 | ||
|
|
5ea9d2fa9f | ||
|
|
b3842de871 | ||
|
|
c17c653eb1 | ||
|
|
78e5d28f65 | ||
|
|
9ad76b3335 | ||
|
|
71d175a4c0 | ||
|
|
01d152fcaa | ||
|
|
3b9fc92d66 | ||
|
|
9ec11e2f8f | ||
|
|
7c780766f4 | ||
|
|
5df0ee7935 | ||
|
|
e1288e79c9 | ||
|
|
1131026be9 | ||
|
|
5e485a085a | ||
|
|
4b494e3e6f | ||
|
|
005d60d6b4 | ||
|
|
b51e2a868b | ||
|
|
a4fe359c28 | ||
|
|
dd8c88b418 | ||
|
|
890f56ac38 | ||
|
|
df13fc3e40 | ||
|
|
b60f2deedb | ||
|
|
7b29a1ae73 | ||
|
|
2bc1a7e327 | ||
|
|
c3ff29cd7f | ||
|
|
0b1d80d3e3 | ||
|
|
7153bda0be | ||
|
|
de867d7a9a | ||
|
|
859168015a | ||
|
|
93ed4e5035 | ||
|
|
0d169dd947 | ||
|
|
b488012d5f | ||
|
|
da4bc44032 | ||
|
|
5d9c6cd02c | ||
|
|
58629db7f3 | ||
|
|
aad91a5b3c | ||
|
|
32ef4ecbea | ||
|
|
5d930ed15c | ||
|
|
ed04c80bb1 | ||
|
|
33f96f051f | ||
|
|
927ee2406a | ||
|
|
a4fe866bff | ||
|
|
fb59b40507 | ||
|
|
1fd23248ff | ||
|
|
3d71d529d2 | ||
|
|
2cbe8fd707 | ||
|
|
473a1f91d5 | ||
|
|
09b90773d8 | ||
|
|
8c95821e9c | ||
|
|
09eb3731f2 | ||
|
|
f93bedee71 | ||
|
|
b7139c38ed | ||
|
|
ddbdcaa3d3 | ||
|
|
dc6e58b17c | ||
|
|
ca36519325 | ||
|
|
eac0a1bba9 | ||
|
|
6fefac368e | ||
|
|
86bfca696a | ||
|
|
366de97ab5 | ||
|
|
834ce171d3 | ||
|
|
5a623cccb5 | ||
|
|
c1a814c235 | ||
|
|
27949eb31c | ||
|
|
c0f0e2ba45 | ||
|
|
8889c5cfd3 | ||
|
|
5b6006f8fe | ||
|
|
ba7eaf3cc7 | ||
|
|
291d2fe2de | ||
|
|
c133a37b7c | ||
|
|
10362ab9b4 | ||
|
|
6a79d17319 | ||
|
|
ef5efda4f5 | ||
|
|
772ee494c5 | ||
|
|
d0f4ede99b | ||
|
|
0adfd68fae | ||
|
|
d557c407c6 | ||
|
|
add7f0b4b0 | ||
|
|
64e67df881 | ||
|
|
26998fca32 | ||
|
|
e60adb01fa | ||
|
|
5fa707bb56 | ||
|
|
786fe64723 | ||
|
|
135b77dab5 | ||
|
|
9377cb376d | ||
|
|
510897a497 | ||
|
|
9fd91bb70a | ||
|
|
57868bafa6 | ||
|
|
7aa1ccf726 | ||
|
|
78739d9417 | ||
|
|
0f3105a01f | ||
|
|
8227b7d16f | ||
|
|
0eb4296519 | ||
|
|
df33a16f78 | ||
|
|
0034944f20 | ||
|
|
053fb3ac19 | ||
|
|
fc28098292 | ||
|
|
834f97606e | ||
|
|
215d305e3d | ||
|
|
de1574d21f | ||
|
|
6cf2fe50dc | ||
|
|
c6e0a69bbc | ||
|
|
718dd26043 | ||
|
|
dd885b7302 | ||
|
|
958cc8b947 | ||
|
|
295300ff46 | ||
|
|
94e20ffee5 | ||
|
|
ff9ffddd57 | ||
|
|
7410c057c6 | ||
|
|
15481e63dd | ||
|
|
d90fac6e09 | ||
|
|
bb54dc97b6 | ||
|
|
b7a4dbb07f | ||
|
|
9207315b25 | ||
|
|
5af537147d | ||
|
|
bac42c5121 | ||
|
|
2cf59a23e7 | ||
|
|
4710ce6f66 | ||
|
|
5a6e12dc97 | ||
|
|
a33b5a9526 | ||
|
|
9b711adfd1 | ||
|
|
0594177191 | ||
|
|
e85dfc7499 | ||
|
|
474ab02d44 | ||
|
|
b0b2e02248 | ||
|
|
4351d033f3 | ||
|
|
062eaa9eac | ||
|
|
6aabd18479 | ||
|
|
0d91dbb681 | ||
|
|
5b8d3068f7 | ||
|
|
673c5ac851 | ||
|
|
4abff16783 | ||
|
|
774c6901a8 | ||
|
|
6b00400d46 | ||
|
|
e8837688a2 | ||
|
|
7caea34671 | ||
|
|
824c9dae32 | ||
|
|
ed2e57dde6 | ||
|
|
7e760f956a | ||
|
|
ebe197b0a8 | ||
|
|
6fda21d717 | ||
|
|
36472802f7 | ||
|
|
694286b30d | ||
|
|
7fafaf81c0 | ||
|
|
69cb7f6b03 | ||
|
|
c18aba39df | ||
|
|
fcef3696bc | ||
|
|
a4d85a88fe | ||
|
|
af50e69293 | ||
|
|
d547bd9f83 | ||
|
|
72fe8cb479 | ||
|
|
fc2c737e05 | ||
|
|
637ec168df | ||
|
|
e5977658f4 | ||
|
|
f47fea3751 | ||
|
|
526a981911 | ||
|
|
7e4f425b79 | ||
|
|
3791008b01 | ||
|
|
f9ef83b4bf | ||
|
|
bd2363178d | ||
|
|
b2fe2c0e3b | ||
|
|
7ae69c70fb | ||
|
|
ff5ff4d294 | ||
|
|
5fc83f4d05 | ||
|
|
556408a6f2 | ||
|
|
fafecdfd17 | ||
|
|
977fefeb1b | ||
|
|
717728f33b | ||
|
|
c38b8b1265 | ||
|
|
1e6afb3b73 | ||
|
|
78f7a96300 | ||
|
|
264a6cc02d | ||
|
|
c2b7e983bf | ||
|
|
1d2901cb98 | ||
|
|
6adfc78043 | ||
|
|
5f1da94971 | ||
|
|
14572aa817 | ||
|
|
e8ed47410f | ||
|
|
7b00bb1ffe | ||
|
|
5a26dba8e5 | ||
|
|
f15a3fbaba | ||
|
|
9077cfdddb | ||
|
|
d962f98a5b | ||
|
|
596f379690 | ||
|
|
4191e25038 | ||
|
|
7c19c5b229 | ||
|
|
d8c3cf11f6 | ||
|
|
4dc805c2ad | ||
|
|
711850fb22 | ||
|
|
e36fb5e622 | ||
|
|
a80639c376 | ||
|
|
7b55e96b51 | ||
|
|
462562a921 | ||
|
|
55cfdd6fe8 | ||
|
|
90e29a7bee | ||
|
|
8fb3f7e40e | ||
|
|
89c9938013 | ||
|
|
53bb57882d | ||
|
|
67a1b3e382 | ||
|
|
78e7e59381 | ||
|
|
75b9fdc0a0 | ||
|
|
dc35f2f40c | ||
|
|
46b7546d51 | ||
|
|
2af3a0c024 | ||
|
|
d411de811a | ||
|
|
d70edbcb7c | ||
|
|
8141fecaa9 | ||
|
|
f27bd1dacb | ||
|
|
98535d5e06 | ||
|
|
a3589e4487 | ||
|
|
c4462ab63e | ||
|
|
b815a0a3dc | ||
|
|
629e03f303 | ||
|
|
c466bb1696 | ||
|
|
47a930ae53 | ||
|
|
7d83349507 | ||
|
|
b3bac0c9e8 | ||
|
|
8d28b72741 | ||
|
|
19ee2a021b | ||
|
|
2780b57f83 | ||
|
|
03b2a40e15 | ||
|
|
6f04b1dbd8 | ||
|
|
8c4d7b431b | ||
|
|
a7bbf56cae | ||
|
|
fda0651bb5 | ||
|
|
30c1608380 | ||
|
|
d55a49a9b2 | ||
|
|
cd00b0090b | ||
|
|
2633bdd838 | ||
|
|
c7da20e53c | ||
|
|
54f1f6b8c9 | ||
|
|
ff3236ef36 | ||
|
|
116e34d7ef | ||
|
|
fcd6a18090 | ||
|
|
9154939d8f | ||
|
|
460c525e03 | ||
|
|
08006bce3d | ||
|
|
e21ea5355f | ||
|
|
892f67bd76 | ||
|
|
a59ee872ff | ||
|
|
3b2d0a19cb | ||
|
|
6673a80db5 | ||
|
|
3e00885ba6 | ||
|
|
c6193699bf | ||
|
|
0c7b3675d8 | ||
|
|
42a7cb1248 | ||
|
|
34fffb90d5 | ||
|
|
d07c379c69 | ||
|
|
b1eb2cf3a7 | ||
|
|
aba6eaf532 | ||
|
|
66c44d24ff | ||
|
|
cf917fc426 | ||
|
|
71ce8845d5 | ||
|
|
a5334eb2b3 | ||
|
|
e6b3ba0178 | ||
|
|
7da629d03b | ||
|
|
2cfe2fe3c3 | ||
|
|
deb1d6812e | ||
|
|
2a67bc6e1d | ||
|
|
f38cbb6134 | ||
|
|
5fd49d4d6a | ||
|
|
f83d828b24 | ||
|
|
310fa67f9d | ||
|
|
a764331a95 | ||
|
|
5cc2358376 | ||
|
|
a06ded53e9 | ||
|
|
901f9c3760 | ||
|
|
217890c822 | ||
|
|
2d46edace9 | ||
|
|
bb33994219 | ||
|
|
d16529dacb | ||
|
|
69ebd2bb85 | ||
|
|
287bfd9fb2 | ||
|
|
510b9cfac6 | ||
|
|
3cc3c9a34e | ||
|
|
e1c9c4297b | ||
|
|
740499a726 | ||
|
|
df5c3d7141 | ||
|
|
e6f3444eb2 | ||
|
|
5301aa4db2 | ||
|
|
68c6443467 | ||
|
|
b41ed492df | ||
|
|
a62edd05de | ||
|
|
34c7acf022 | ||
|
|
28f7874942 | ||
|
|
db92b99ec1 | ||
|
|
15ae22c680 | ||
|
|
c4ded2fc07 | ||
|
|
65f509db40 | ||
|
|
0c8b451a00 | ||
|
|
780a892eb4 | ||
|
|
1a1bd38495 | ||
|
|
3383e6adc0 | ||
|
|
d266c665b0 | ||
|
|
e02b40f04f | ||
|
|
76ff938e00 | ||
|
|
a06e685cfc | ||
|
|
6cd1240fa2 | ||
|
|
0ded061037 | ||
|
|
a109ef9cbe | ||
|
|
665b873c96 | ||
|
|
956f4d5e14 | ||
|
|
0f5e56289e | ||
|
|
f2ebeaa7e4 | ||
|
|
cc1d23a94c | ||
|
|
6ff99315a1 | ||
|
|
7e46fc1d8f | ||
|
|
d30e120608 | ||
|
|
ef8ab20a31 | ||
|
|
1b5797be9d | ||
|
|
b6f3513173 | ||
|
|
aafafce083 | ||
|
|
441c70750c | ||
|
|
de271fe729 | ||
|
|
4e1e9ecf3e | ||
|
|
4b74aa5768 | ||
|
|
56d13534b4 | ||
|
|
bbc2657023 | ||
|
|
0a471bb12c | ||
|
|
06acda0ab9 | ||
|
|
cb6767a02b | ||
|
|
b026de2feb | ||
|
|
d575c3a5f7 | ||
|
|
3932b81401 | ||
|
|
f1b3837186 | ||
|
|
3c9fa8609a | ||
|
|
fe4a8dc183 | ||
|
|
389d148a60 | ||
|
|
908d47305b | ||
|
|
bf315e63d7 | ||
|
|
cab0c74e08 | ||
|
|
be97a2e4a5 | ||
|
|
e266f3b955 | ||
|
|
f1b8e1a7b0 | ||
|
|
6a403df100 | ||
|
|
38e0dbb236 | ||
|
|
ab5b69c5e4 | ||
|
|
21b78514f5 | ||
|
|
fb34d2b9e3 | ||
|
|
2b0492c6d6 | ||
|
|
2e557573f4 | ||
|
|
be6b88f406 | ||
|
|
0a6c939a73 | ||
|
|
a846ac9b39 | ||
|
|
d244749f1a | ||
|
|
16ab71d302 | ||
|
|
5dacd51b91 | ||
|
|
19f7fd304d | ||
|
|
e0d64c5ac6 | ||
|
|
4f8015b58a | ||
|
|
9f4fb428c9 | ||
|
|
bdc8f7a2cb | ||
|
|
5a3ab5c5f0 | ||
|
|
6092854ece | ||
|
|
02176ec5f8 | ||
|
|
02631155dc | ||
|
|
a5ef629cef | ||
|
|
9b6afd82aa | ||
|
|
4553af505f | ||
|
|
61f120222f | ||
|
|
b79b3d0c00 | ||
|
|
610ed0dc13 | ||
|
|
399c171f03 | ||
|
|
7e92e888bf | ||
|
|
7b14d445b4 | ||
|
|
61156afd90 | ||
|
|
347c2ed498 | ||
|
|
4dd6f6400c | ||
|
|
c0eb4b39ac | ||
|
|
55618f20d4 | ||
|
|
d7db55af39 | ||
|
|
c1233291bc | ||
|
|
0f2043d874 | ||
|
|
068f6a2e83 | ||
|
|
1efb8b4cc0 | ||
|
|
328439a8bf | ||
|
|
a44e80c829 | ||
|
|
041d70a7ff | ||
|
|
86457e5201 | ||
|
|
59b2908620 | ||
|
|
658681d002 | ||
|
|
d41a07161d | ||
|
|
fc13794f5f | ||
|
|
d4c8be92b0 | ||
|
|
0313ab4e49 | ||
|
|
bbfa66636d | ||
|
|
59e5144122 | ||
|
|
6ecc96d193 | ||
|
|
0ccc9f65a6 | ||
|
|
af87b9aa98 | ||
|
|
0484496d92 | ||
|
|
fbf6596f20 | ||
|
|
55d88440eb | ||
|
|
f53bd6bdba | ||
|
|
faebc4c948 | ||
|
|
55cfebb439 | ||
|
|
d388566d5c | ||
|
|
3e226b5aaa | ||
|
|
5cc4f8132a | ||
|
|
a778917806 | ||
|
|
2e4ed57363 | ||
|
|
4e987163af | ||
|
|
1794862d73 | ||
|
|
937eba4785 | ||
|
|
2c87890758 | ||
|
|
973dbd6a13 | ||
|
|
c1048a0353 | ||
|
|
896f0c69fc | ||
|
|
fcb6255161 | ||
|
|
f18bef867e | ||
|
|
6504b914ba | ||
|
|
6e92d6a6f0 | ||
|
|
7e9f9106c9 | ||
|
|
69626272d5 | ||
|
|
eed44d12ba | ||
|
|
2a61b241a8 | ||
|
|
a92d59317c | ||
|
|
1d67dcfa3c | ||
|
|
14ec9a2068 | ||
|
|
045e597787 | ||
|
|
89a6b6842c | ||
|
|
8ce35e30dd | ||
|
|
6569cf8e0c | ||
|
|
58769b1d75 | ||
|
|
a12e5884ab | ||
|
|
3fcf7a0344 | ||
|
|
8be4375288 | ||
|
|
f07c7377b6 | ||
|
|
7929a335c3 | ||
|
|
5411ebb806 | ||
|
|
ede57c0b12 | ||
|
|
56dd3f40e0 | ||
|
|
13de81b3b2 | ||
|
|
65648e6469 | ||
|
|
6a6bcd09ee | ||
|
|
5dfb8c9474 | ||
|
|
a99a7fc484 | ||
|
|
973de3239f | ||
|
|
b888385ba1 | ||
|
|
6c70ef7c7d | ||
|
|
7c73dbfba9 | ||
|
|
1cdb008bd5 | ||
|
|
770ee8b54d | ||
|
|
4aa30c1a51 | ||
|
|
171ce39e8c | ||
|
|
18199ff323 | ||
|
|
0b5e63b7c3 | ||
|
|
c501f55695 | ||
|
|
c3b208869a | ||
|
|
f0dae546b5 | ||
|
|
d1a18c15e6 | ||
|
|
7f115954fd | ||
|
|
5c5fe09990 | ||
|
|
45c1b268f1 | ||
|
|
903731adaf | ||
|
|
da96f06202 | ||
|
|
ac7dc28cfb | ||
|
|
0784e57082 | ||
|
|
a445979f1a | ||
|
|
ce0f9922ee | ||
|
|
b2f94e4239 | ||
|
|
5b9baba900 | ||
|
|
9a45ffd459 | ||
|
|
7d841dbfa8 | ||
|
|
cc09c5b6d9 | ||
|
|
5a117d8edf | ||
|
|
802f16c542 | ||
|
|
66237415c5 | ||
|
|
5ca1be567d | ||
|
|
b1bd8a4394 | ||
|
|
e3b9ba01c2 | ||
|
|
2c00b92325 | ||
|
|
15f19adc6e | ||
|
|
16690fc1d4 | ||
|
|
c9b4dab1e1 | ||
|
|
99796220f9 | ||
|
|
9af64c9b21 | ||
|
|
56570a2200 | ||
|
|
8e0d33a1fd | ||
|
|
56a892e5f9 | ||
|
|
c0a242a1eb | ||
|
|
0bc41d562d | ||
|
|
2b9c05d395 | ||
|
|
d16de56280 | ||
|
|
b049c5a7d1 | ||
|
|
ba0f7d703e | ||
|
|
aff1d02046 | ||
|
|
124de31055 | ||
|
|
24e3a4218b | ||
|
|
fe73c9fb71 | ||
|
|
77cf6e49a0 | ||
|
|
c97af35176 | ||
|
|
bc5e298e2b | ||
|
|
411c82ae8f | ||
|
|
b838ed4e85 | ||
|
|
7842016228 | ||
|
|
2808c91280 | ||
|
|
fbedff79ab | ||
|
|
f7e9f78ee3 | ||
|
|
ea3defe357 | ||
|
|
1ea11a748d | ||
|
|
c86e864d55 | ||
|
|
55f089d997 | ||
|
|
d370e0ae2d | ||
|
|
18fc3337ff | ||
|
|
7175b1dd65 | ||
|
|
24ed43d541 | ||
|
|
f59eb94d92 | ||
|
|
47f0898ce9 | ||
|
|
8942967223 | ||
|
|
4ad57fe2d5 | ||
|
|
ad980b4966 | ||
|
|
ce8ec242f9 | ||
|
|
ce2a500a06 | ||
|
|
ec9db30863 | ||
|
|
92e4507cf7 | ||
|
|
e7aec53631 | ||
|
|
40113933b4 | ||
|
|
63ba9bd018 | ||
|
|
63c62c49ce | ||
|
|
0c8e6b822c | ||
|
|
7279a80dfa | ||
|
|
8099621cd0 | ||
|
|
c5a96fdd08 | ||
|
|
4b44e4e73a | ||
|
|
7b9ab5e292 | ||
|
|
4b0ae7ef9a | ||
|
|
ee30b6e888 | ||
|
|
837aba777f | ||
|
|
9a182bb247 | ||
|
|
45fdcaea45 | ||
|
|
0fd142153a | ||
|
|
636bf90f84 | ||
|
|
31d9abfc8c | ||
|
|
655d6f6720 | ||
|
|
9936439608 | ||
|
|
ff4d9ecc77 | ||
|
|
0503592af7 | ||
|
|
8489fb258a | ||
|
|
2c7aa318c1 | ||
|
|
055a8efe10 | ||
|
|
746669046a | ||
|
|
171e0d0e4b | ||
|
|
0770b77336 | ||
|
|
4346f7d59d | ||
|
|
70cac6ce08 | ||
|
|
135ff85356 | ||
|
|
7b0b1b5977 | ||
|
|
5946aa7a3a | ||
|
|
53d239aa8f | ||
|
|
82e2cd4746 | ||
|
|
59ec727191 | ||
|
|
495b4ba841 | ||
|
|
3030e3a74f | ||
|
|
e2691f3b3d | ||
|
|
dd6398dbcb | ||
|
|
5b73b48dc8 | ||
|
|
a359df93c9 | ||
|
|
4c422c2d50 | ||
|
|
1b0d87cafd | ||
|
|
5c63581bd5 | ||
|
|
e89eb56a44 | ||
|
|
00d18ca479 | ||
|
|
46f07faead | ||
|
|
44de824fe3 | ||
|
|
f48681a61d | ||
|
|
f6b17a7f3c | ||
|
|
92bb5bd915 | ||
|
|
be29f3bd99 | ||
|
|
a03d8b3c3f | ||
|
|
f8725ac3bd | ||
|
|
a3abff768c | ||
|
|
1fd1c2edbd | ||
|
|
131928ee53 | ||
|
|
1761823efe | ||
|
|
cfdbc2312d | ||
|
|
a2de752a33 | ||
|
|
4c1968f62a | ||
|
|
a53fff7608 | ||
|
|
6d02ac0290 | ||
|
|
cff68a14d8 | ||
|
|
c1ac986f20 | ||
|
|
472cf20b81 | ||
|
|
936ead016e | ||
|
|
24529bf35d | ||
|
|
2bab5d1ddd | ||
|
|
1f57d9462c | ||
|
|
73e973c29b | ||
|
|
8e7ac226b0 | ||
|
|
afab9395b9 | ||
|
|
5d6fcbeccf | ||
|
|
408c9a7b33 | ||
|
|
9aec1e9484 | ||
|
|
24f4c96fc3 | ||
|
|
6893dbb657 | ||
|
|
edd7151184 | ||
|
|
b8f1264e71 | ||
|
|
a7c372efff | ||
|
|
a6d1323eba | ||
|
|
8f585713fa | ||
|
|
d27ff60ae2 | ||
|
|
c059934fe8 | ||
|
|
76ce3b9d94 | ||
|
|
2db86111b2 | ||
|
|
a8997dc35c | ||
|
|
a3c686d317 | ||
|
|
81a2792e37 | ||
|
|
ff8894f2ec | ||
|
|
020f3a173a | ||
|
|
73f5c68674 | ||
|
|
7f75cd71da | ||
|
|
eb17b2f371 | ||
|
|
db863a4de7 | ||
|
|
5ad33896cc | ||
|
|
379a4655b0 | ||
|
|
b1b7c4257b | ||
|
|
98ef8e4ef2 | ||
|
|
ddd1f21e5d | ||
|
|
a381a4174e | ||
|
|
4895c895aa | ||
|
|
88352c74fc | ||
|
|
36d5880a30 | ||
|
|
de544b5316 | ||
|
|
cea46d8c8c | ||
|
|
72a1ed2fa3 | ||
|
|
1cb2b0ac1c | ||
|
|
57bda914f9 | ||
|
|
fe71d5b42d | ||
|
|
8a3b7c575f | ||
|
|
47d9335658 | ||
|
|
19ed695811 | ||
|
|
1f967c6f63 | ||
|
|
2165728088 | ||
|
|
156a14eeeb | ||
|
|
97088e3109 | ||
|
|
2b597fb780 | ||
|
|
efeaa9b6ad | ||
|
|
d7f710806b | ||
|
|
d92362f96e | ||
|
|
8fea872345 | ||
|
|
84c0b50aa1 | ||
|
|
f523b17a35 | ||
|
|
ee5639aad9 | ||
|
|
be4112ee68 | ||
|
|
628c590c00 | ||
|
|
24fd125223 | ||
|
|
d8c81e712e | ||
|
|
cc8670b956 | ||
|
|
07cf84cbc7 | ||
|
|
ffbfa84591 | ||
|
|
b6e250303e | ||
|
|
92a6ba8a57 | ||
|
|
d9de9b7cb4 | ||
|
|
ad297f28b8 | ||
|
|
5d7d633595 | ||
|
|
1436e21761 | ||
|
|
4380106d3e | ||
|
|
ce0b99ee9d | ||
|
|
77fc23c4d1 | ||
|
|
b2d14380b4 | ||
|
|
42c9e08595 | ||
|
|
cb2dfb2e11 | ||
|
|
0fea67f662 | ||
|
|
e82d2ee8ee | ||
|
|
e530ff93c4 | ||
|
|
494c3bc487 | ||
|
|
bd2ff4e909 | ||
|
|
728a47ab99 | ||
|
|
f3026a9ee6 | ||
|
|
3d1225bf34 | ||
|
|
b6ef7d5910 | ||
|
|
f67bbbc457 | ||
|
|
14c615dead | ||
|
|
0092bff922 | ||
|
|
41f6d62a51 | ||
|
|
40712b1026 | ||
|
|
252c2b0c96 | ||
|
|
52782b6def | ||
|
|
57adda40f9 | ||
|
|
edb4a1ee9e | ||
|
|
9dfe8851f8 | ||
|
|
3cd79b6fec | ||
|
|
796af1351c | ||
|
|
bccaf69712 | ||
|
|
1902049972 | ||
|
|
375a6b4d38 | ||
|
|
8e489cdbdb | ||
|
|
8c58fcb1cc | ||
|
|
547bf93f4a | ||
|
|
1a5af8cafd | ||
|
|
4b9317d1f0 | ||
|
|
f92ef92193 | ||
|
|
958f74340b | ||
|
|
c06dc750da | ||
|
|
aa405b2176 | ||
|
|
13176e8b53 | ||
|
|
05d703e53b | ||
|
|
b3cde66bd2 | ||
|
|
aac3c448a4 | ||
|
|
8ad1af106d | ||
|
|
b5674f12f0 | ||
|
|
1f5aa7fb7d | ||
|
|
7fc7221348 | ||
|
|
a39bc94c58 | ||
|
|
d9d3ccf6c6 | ||
|
|
1467fe4226 | ||
|
|
222f3d876c | ||
|
|
9b92e145e7 | ||
|
|
9df0cdf193 | ||
|
|
9e7eb3feef | ||
|
|
8b9dbc22e5 | ||
|
|
2184f21dd2 | ||
|
|
3b698db127 | ||
|
|
2a70ff3cf3 | ||
|
|
55867ab48b | ||
|
|
d38296a553 | ||
|
|
4db8351348 | ||
|
|
cdada6e889 | ||
|
|
4d4f8c1f9c | ||
|
|
f49b328e17 | ||
|
|
e3d3887a0b | ||
|
|
ffaeb89347 | ||
|
|
8586b98c1a | ||
|
|
9690e84722 | ||
|
|
65f04da920 | ||
|
|
6fe92ff13c | ||
|
|
793d332002 | ||
|
|
e06cfd24cf | ||
|
|
a59ca7536a | ||
|
|
83fd743db8 | ||
|
|
fad9412c04 | ||
|
|
8898eb8206 | ||
|
|
33673a30c7 | ||
|
|
21f02924c1 | ||
|
|
806f7b33aa | ||
|
|
ca37a9086f | ||
|
|
f9e495ac49 | ||
|
|
8f70192bf3 | ||
|
|
05bc399afc | ||
|
|
78c0b8f985 | ||
|
|
06bcde9c2d | ||
|
|
86f3c0916e | ||
|
|
a9631587f0 | ||
|
|
f577c2120c | ||
|
|
e620df4c43 | ||
|
|
450b0b8acb | ||
|
|
4065c94c1f | ||
|
|
920c43f589 | ||
|
|
744fc321e9 | ||
|
|
e2150fd66e | ||
|
|
20817dc51d | ||
|
|
617d34b9de | ||
|
|
4051533cc4 | ||
|
|
2bc21be319 | ||
|
|
ebc27d314b | ||
|
|
845502f522 | ||
|
|
4980cb4c92 | ||
|
|
b565215d58 | ||
|
|
32d092b293 | ||
|
|
a74812ba12 | ||
|
|
b24920c606 | ||
|
|
c395e40963 | ||
|
|
164e2214c3 | ||
|
|
170cc0e275 | ||
|
|
e721b8910c | ||
|
|
fc637552b7 | ||
|
|
8c47b13d9e | ||
|
|
ced1d6e087 | ||
|
|
1bbfb7cffd | ||
|
|
10f7750d80 | ||
|
|
e4a9a16161 | ||
|
|
780596477c | ||
|
|
cb0bb31d06 | ||
|
|
a03f325ffa | ||
|
|
a4ee6e27b9 | ||
|
|
593d2fce21 | ||
|
|
f0569bd3c4 | ||
|
|
1da6937a0f | ||
|
|
83b1b94034 | ||
|
|
7f1c9c89e7 | ||
|
|
dd23715942 | ||
|
|
38cf04b888 | ||
|
|
9777ddd2b7 | ||
|
|
a0af4d4d2b | ||
|
|
e970fa09b0 | ||
|
|
5ab39592cf | ||
|
|
5f1a27d52b | ||
|
|
d57877af31 | ||
|
|
d399312786 | ||
|
|
8c4dc60e75 | ||
|
|
01487d5ad3 | ||
|
|
5bea676ce3 | ||
|
|
f59d6b971b | ||
|
|
2ef195583f | ||
|
|
c19a254498 | ||
|
|
14256e22d3 | ||
|
|
368d07ad9c | ||
|
|
9404c859cb | ||
|
|
9eb049a833 | ||
|
|
ec2b62c042 | ||
|
|
f3bea4aa8b | ||
|
|
1283a89a95 | ||
|
|
29460c440d | ||
|
|
5963a2c82e | ||
|
|
6a3320b113 | ||
|
|
9230b22ea4 | ||
|
|
c1888035ac | ||
|
|
f784a9098f | ||
|
|
a875473670 | ||
|
|
1515cffb5d | ||
|
|
7da71113a7 | ||
|
|
e75536581a | ||
|
|
16d40dfd15 | ||
|
|
2dd3cc4875 | ||
|
|
9209a5f186 | ||
|
|
fda71dbf53 | ||
|
|
f2744cf099 | ||
|
|
6850784b1e | ||
|
|
afc45d4b6e | ||
|
|
c19538f834 | ||
|
|
069c3b2468 | ||
|
|
26b8ff722d | ||
|
|
61616264b1 | ||
|
|
9d548f7432 | ||
|
|
4c010a03af | ||
|
|
92e77fbba5 | ||
|
|
c0d619cd86 | ||
|
|
cd464ef916 | ||
|
|
65efbfce12 | ||
|
|
e854090bdd | ||
|
|
8fc0fd3221 | ||
|
|
7b387ba4b2 | ||
|
|
5f3a3c76dd | ||
|
|
1c35692235 | ||
|
|
f2649af5a1 | ||
|
|
1dfca2ff76 | ||
|
|
0cd4e0413f | ||
|
|
5f3990d1bc | ||
|
|
c9dd3b3238 | ||
|
|
1f1e291cd1 | ||
|
|
de07fe8aaf | ||
|
|
5326cb55b3 | ||
|
|
55e54593cc | ||
|
|
7c7b9b6a63 | ||
|
|
25993479b1 | ||
|
|
32cf7ec677 | ||
|
|
d4d58047b0 | ||
|
|
8f682303ca | ||
|
|
52afe582e1 | ||
|
|
a2933084ca | ||
|
|
8006f12dea | ||
|
|
b7be24d775 | ||
|
|
0fc5ebf5b1 | ||
|
|
b592a67892 | ||
|
|
f2cce14390 | ||
|
|
70615df273 | ||
|
|
9b29210dce | ||
|
|
a6d0938385 | ||
|
|
0bc12be059 | ||
|
|
c29cb87d2f | ||
|
|
dcfd0943d5 | ||
|
|
25bd37364c | ||
|
|
4a6c5c25b0 | ||
|
|
8c824dfaf7 | ||
|
|
5977db8833 | ||
|
|
abb433aa42 | ||
|
|
2c98869d96 | ||
|
|
0cf0240cb5 | ||
|
|
9339232946 | ||
|
|
b17b226220 | ||
|
|
431a15c14a | ||
|
|
ffc966a9ad | ||
|
|
58922b7e76 | ||
|
|
5874d90719 | ||
|
|
c694853ddb | ||
|
|
fdc2e4a67a | ||
|
|
fcaaae705d | ||
|
|
ba291a9254 | ||
|
|
feb97789c5 | ||
|
|
c99952d8cd | ||
|
|
7c07e3406e | ||
|
|
0730ece757 | ||
|
|
c8928ff5d9 | ||
|
|
c4b928d441 | ||
|
|
afebab334e | ||
|
|
bbbe16531b | ||
|
|
089c769373 | ||
|
|
9be406482b | ||
|
|
353ecbc62d | ||
|
|
ed6202d202 | ||
|
|
617e3135c1 | ||
|
|
2dfa38f572 | ||
|
|
e8e90300f0 | ||
|
|
3081a1b9c7 | ||
|
|
0ce42d520a | ||
|
|
db93e784ab | ||
|
|
8c63b25704 | ||
|
|
f22942b3c8 | ||
|
|
a975f018c5 | ||
|
|
817e699738 | ||
|
|
d8f357b01c | ||
|
|
cd892105f6 | ||
|
|
2900bb099f | ||
|
|
bb4983ee39 | ||
|
|
dce6d8e4ae | ||
|
|
01828ef885 | ||
|
|
290b7ebd26 | ||
|
|
6842b4cb46 | ||
|
|
40060e3525 | ||
|
|
68e279b399 | ||
|
|
15e9d6ba5a | ||
|
|
a9443774a9 | ||
|
|
e40c5d441d | ||
|
|
88ad4858ec | ||
|
|
2fc1114ad2 | ||
|
|
ea4c93a044 | ||
|
|
80c774ec49 | ||
|
|
0b4979d20a | ||
|
|
dadcfb8101 | ||
|
|
e035f05564 | ||
|
|
0a3d61435e | ||
|
|
6ce8cda0a3 | ||
|
|
d255b7d6e9 | ||
|
|
9476452c49 | ||
|
|
2fec889a11 | ||
|
|
dbca774e17 | ||
|
|
d5a4051c7f | ||
|
|
732ea1b882 | ||
|
|
0e195410b5 | ||
|
|
63e3ee222b | ||
|
|
b31c8a56f7 | ||
|
|
ed6c957001 | ||
|
|
94073cfb5a | ||
|
|
cacb797d16 | ||
|
|
47901c3fb7 | ||
|
|
c45a376dd6 | ||
|
|
9e77a046a1 | ||
|
|
628d90353d | ||
|
|
cec0b3c15f | ||
|
|
300264bee1 | ||
|
|
d1c15a2666 | ||
|
|
5649f5a87f | ||
|
|
9c5d2fff1a | ||
|
|
fc4fa38c9b | ||
|
|
2f22fa416d | ||
|
|
c8b9846705 | ||
|
|
1dc80d4c04 | ||
|
|
ed8569eb99 | ||
|
|
4b4368a898 | ||
|
|
d04c304c93 | ||
|
|
da236a26fc | ||
|
|
65b91a95d2 | ||
|
|
9b40fa6c76 | ||
|
|
70263b6fba | ||
|
|
e5b838bac8 | ||
|
|
888267520d | ||
|
|
b82d26aee7 | ||
|
|
15722b4bb9 | ||
|
|
175b0e88a3 | ||
|
|
944ba527f3 | ||
|
|
8a5a5022ce | ||
|
|
5a24c2dc5d | ||
|
|
8bf95879f7 | ||
|
|
939610a930 | ||
|
|
bcea739cff | ||
|
|
0279e8a34a | ||
|
|
835ca2801c | ||
|
|
f5c78e67b0 | ||
|
|
cd31b6721c | ||
|
|
0225142b90 | ||
|
|
fb495e98b4 | ||
|
|
68eb35e0f4 | ||
|
|
9b5968f170 | ||
|
|
17eb1f8ae1 | ||
|
|
572cf16a51 | ||
|
|
4d19bebc03 | ||
|
|
2d6f0cc589 | ||
|
|
bd766ab3cd | ||
|
|
edfbe71b0f | ||
|
|
52ff34c13e | ||
|
|
b001a73da1 | ||
|
|
591ea245bc | ||
|
|
c63fc61a52 | ||
|
|
8c2bdf984c | ||
|
|
90b855094e | ||
|
|
c4e9a77be4 | ||
|
|
4ce9d005dd | ||
|
|
cb318cf2e9 | ||
|
|
731660c76f | ||
|
|
367062aee4 | ||
|
|
73839692d9 | ||
|
|
debf107b54 | ||
|
|
e62515c042 | ||
|
|
f6b12a33a2 | ||
|
|
248a362c3e | ||
|
|
0dfbb7d83e | ||
|
|
db5f1d2235 | ||
|
|
75670290fe | ||
|
|
ddf5cce6dd | ||
|
|
943197e65c | ||
|
|
54289225e8 | ||
|
|
82343460dd | ||
|
|
74095b25c5 | ||
|
|
2715ff763f | ||
|
|
3ec83f2318 | ||
|
|
9d0d15d51c | ||
|
|
2aa9b16dbc | ||
|
|
08a5030b46 | ||
|
|
c80099173e | ||
|
|
ee34cf612f | ||
|
|
7463ee72d0 | ||
|
|
032b2d877c | ||
|
|
3a2047dcd7 | ||
|
|
85d40a318b | ||
|
|
a77c19a60d | ||
|
|
793bf7f579 | ||
|
|
7c6a884980 | ||
|
|
f121570d60 | ||
|
|
93453ed683 | ||
|
|
7566d75aeb | ||
|
|
49461b2e68 | ||
|
|
a3747f8c71 | ||
|
|
347e788eb6 | ||
|
|
6413108dc9 | ||
|
|
e3b05e51b1 | ||
|
|
72ca563a1d | ||
|
|
03f31d74f1 |
+116
-17
@@ -5,7 +5,7 @@ orbs:
|
||||
executors:
|
||||
golang:
|
||||
docker:
|
||||
- image: circleci/golang:1.14.2
|
||||
- image: circleci/golang:1.14.6
|
||||
resource_class: 2xlarge
|
||||
ubuntu:
|
||||
docker:
|
||||
@@ -93,10 +93,10 @@ jobs:
|
||||
- store_artifacts:
|
||||
path: lotus
|
||||
- store_artifacts:
|
||||
path: lotus-storage-miner
|
||||
path: lotus-miner
|
||||
- store_artifacts:
|
||||
path: lotus-seal-worker
|
||||
- run: mkdir linux && mv lotus lotus-storage-miner lotus-seal-worker linux/
|
||||
path: lotus-worker
|
||||
- run: mkdir linux && mv lotus lotus-miner lotus-worker linux/
|
||||
- persist_to_workspace:
|
||||
root: "."
|
||||
paths:
|
||||
@@ -113,7 +113,7 @@ jobs:
|
||||
test: &test
|
||||
description: |
|
||||
Run tests with gotestsum.
|
||||
parameters:
|
||||
parameters: &test-params
|
||||
executor:
|
||||
type: executor
|
||||
default: golang
|
||||
@@ -134,7 +134,7 @@ jobs:
|
||||
description: Test suite name to report to CircleCI.
|
||||
gotestsum-format:
|
||||
type: string
|
||||
default: short
|
||||
default: pkgname-and-test-fails
|
||||
description: gotestsum format. https://github.com/gotestyourself/gotestsum#format
|
||||
coverage:
|
||||
type: string
|
||||
@@ -156,21 +156,28 @@ jobs:
|
||||
- download-params
|
||||
- go/install-gotestsum:
|
||||
gobin: $HOME/.local/bin
|
||||
version: 0.5.2
|
||||
- run:
|
||||
name: go test
|
||||
environment:
|
||||
GOTESTSUM_JUNITFILE: /tmp/test-reports/<< parameters.test-suite-name >>/junit.xml
|
||||
GOTESTSUM_FORMAT: << parameters.gotestsum-format >>
|
||||
LOTUS_TEST_WINDOW_POST: << parameters.winpost-test >>
|
||||
SKIP_CONFORMANCE: "1"
|
||||
command: |
|
||||
mkdir -p /tmp/test-reports/<< parameters.test-suite-name >>
|
||||
gotestsum -- \
|
||||
mkdir -p /tmp/test-artifacts
|
||||
gotestsum \
|
||||
--format << parameters.gotestsum-format >> \
|
||||
--junitfile /tmp/test-reports/<< parameters.test-suite-name >>/junit.xml \
|
||||
--jsonfile /tmp/test-artifacts/<< parameters.test-suite-name >>.json \
|
||||
-- \
|
||||
<< parameters.coverage >> \
|
||||
<< parameters.go-test-flags >> \
|
||||
<< parameters.packages >>
|
||||
no_output_timeout: 30m
|
||||
- store_test_results:
|
||||
path: /tmp/test-reports
|
||||
- store_artifacts:
|
||||
path: /tmp/test-artifacts/<< parameters.test-suite-name >>.json
|
||||
- when:
|
||||
condition: << parameters.codecov-upload >>
|
||||
steps:
|
||||
@@ -185,6 +192,68 @@ jobs:
|
||||
<<: *test
|
||||
test-window-post:
|
||||
<<: *test
|
||||
test-conformance:
|
||||
description: |
|
||||
Run tests using a corpus of interoperable test vectors for Filecoin
|
||||
implementations to test their correctness and compliance with the Filecoin
|
||||
specifications.
|
||||
parameters:
|
||||
<<: *test-params
|
||||
vectors-branch:
|
||||
type: string
|
||||
default: ""
|
||||
description: |
|
||||
Branch on github.com/filecoin-project/test-vectors to checkout and
|
||||
test with. If empty (the default) the commit defined by the git
|
||||
submodule is used.
|
||||
executor: << parameters.executor >>
|
||||
steps:
|
||||
- install-deps
|
||||
- prepare
|
||||
- run:
|
||||
command: make deps lotus
|
||||
no_output_timeout: 30m
|
||||
- download-params
|
||||
- when:
|
||||
condition:
|
||||
not:
|
||||
equal: [ "", << parameters.vectors-branch >> ]
|
||||
steps:
|
||||
- run:
|
||||
name: checkout vectors branch
|
||||
command: |
|
||||
cd extern/test-vectors
|
||||
git fetch
|
||||
git checkout origin/<< parameters.vectors-branch >>
|
||||
- go/install-gotestsum:
|
||||
gobin: $HOME/.local/bin
|
||||
version: 0.5.2
|
||||
- run:
|
||||
name: install statediff globally
|
||||
command: |
|
||||
## statediff is optional; we succeed even if compilation fails.
|
||||
mkdir -p /tmp/statediff
|
||||
git clone https://github.com/filecoin-project/statediff.git /tmp/statediff
|
||||
cd /tmp/statediff
|
||||
go install ./cmd/statediff || exit 0
|
||||
- run:
|
||||
name: go test
|
||||
environment:
|
||||
SKIP_CONFORMANCE: "0"
|
||||
command: |
|
||||
mkdir -p /tmp/test-reports
|
||||
mkdir -p /tmp/test-artifacts
|
||||
gotestsum \
|
||||
--format pkgname-and-test-fails \
|
||||
--junitfile /tmp/test-reports/junit.xml \
|
||||
-- \
|
||||
-v -coverpkg ./chain/vm/,github.com/filecoin-project/specs-actors/... -coverprofile=/tmp/conformance.out ./conformance/
|
||||
go tool cover -html=/tmp/conformance.out -o /tmp/test-artifacts/conformance-coverage.html
|
||||
no_output_timeout: 30m
|
||||
- store_test_results:
|
||||
path: /tmp/test-reports
|
||||
- store_artifacts:
|
||||
path: /tmp/test-artifacts/conformance-coverage.html
|
||||
|
||||
build-macos:
|
||||
description: build darwin lotus binary
|
||||
@@ -223,10 +292,10 @@ jobs:
|
||||
- store_artifacts:
|
||||
path: lotus
|
||||
- store_artifacts:
|
||||
path: lotus-storage-miner
|
||||
path: lotus-miner
|
||||
- store_artifacts:
|
||||
path: lotus-seal-worker
|
||||
- run: mkdir darwin && mv lotus lotus-storage-miner lotus-seal-worker darwin/
|
||||
path: lotus-worker
|
||||
- run: mkdir darwin && mv lotus lotus-miner lotus-worker darwin/
|
||||
- persist_to_workspace:
|
||||
root: "."
|
||||
paths:
|
||||
@@ -246,6 +315,27 @@ jobs:
|
||||
- run:
|
||||
command: "! go fmt ./... 2>&1 | read"
|
||||
|
||||
cbor-gen-check:
|
||||
executor: golang
|
||||
steps:
|
||||
- install-deps
|
||||
- prepare
|
||||
- run: make deps
|
||||
- run: go install golang.org/x/tools/cmd/goimports
|
||||
- run: go install github.com/hannahhoward/cbor-gen-for
|
||||
- run: go generate ./...
|
||||
- run: git --no-pager diff
|
||||
- run: git --no-pager diff --quiet
|
||||
|
||||
docs-check:
|
||||
executor: golang
|
||||
steps:
|
||||
- install-deps
|
||||
- prepare
|
||||
- run: make docsgen
|
||||
- run: git --no-pager diff
|
||||
- run: git --no-pager diff --quiet
|
||||
|
||||
lint: &lint
|
||||
description: |
|
||||
Run golangci-lint.
|
||||
@@ -282,9 +372,6 @@ jobs:
|
||||
command: |
|
||||
$HOME/.local/bin/golangci-lint run -v --timeout 2m \
|
||||
--concurrency << parameters.concurrency >> << parameters.args >>
|
||||
lint-changes:
|
||||
<<: *lint
|
||||
|
||||
lint-all:
|
||||
<<: *lint
|
||||
|
||||
@@ -313,21 +400,33 @@ workflows:
|
||||
version: 2.1
|
||||
ci:
|
||||
jobs:
|
||||
- lint-changes:
|
||||
args: "--new-from-rev origin/master"
|
||||
- lint-all
|
||||
- mod-tidy-check
|
||||
- gofmt
|
||||
- cbor-gen-check
|
||||
- docs-check
|
||||
- test:
|
||||
codecov-upload: true
|
||||
test-suite-name: full
|
||||
- test-window-post:
|
||||
go-test-flags: "-run=TestWindowedPost"
|
||||
winpost-test: "1"
|
||||
test-suite-name: window-post
|
||||
- test-short:
|
||||
go-test-flags: "--timeout 10m --short"
|
||||
test-suite-name: short
|
||||
filters:
|
||||
tags:
|
||||
only:
|
||||
- /^v\d+\.\d+\.\d+$/
|
||||
- test-conformance:
|
||||
test-suite-name: conformance
|
||||
packages: "./conformance"
|
||||
- test-conformance:
|
||||
name: test-conformance-bleeding-edge
|
||||
test-suite-name: conformance-bleeding-edge
|
||||
packages: "./conformance"
|
||||
vectors-branch: master
|
||||
- build-debug
|
||||
- build-all:
|
||||
requires:
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
comment: off
|
||||
ignore:
|
||||
- "cbor_gen.go"
|
||||
github_checks:
|
||||
annotations: false
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
## filecoin-project/lotus CODEOWNERS
|
||||
## Refer to https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners.
|
||||
##
|
||||
## These users or groups will be automatically assigned as reviewers every time
|
||||
## a PR is submitted that modifies code in the specified locations.
|
||||
##
|
||||
## The Lotus repo configuration requires that at least ONE codeowner approves
|
||||
## the PR before merging.
|
||||
|
||||
### Global owners.
|
||||
* @magik6k @whyrusleeping @Kubuxu
|
||||
|
||||
### Conformance testing.
|
||||
conformance/ @raulk
|
||||
extern/test-vectors @raulk
|
||||
@@ -17,18 +17,27 @@ A brief description of the problem you encountered while proving (sealing) a sec
|
||||
|
||||
Including what commands you ran, and a description of your setup, is very helpful.
|
||||
|
||||
**Sectors list**
|
||||
|
||||
The output of `./lotus-storage-miner sectors list`.
|
||||
|
||||
**Sectors status**
|
||||
|
||||
The output of `./lotus-storage-miner sectors status --log <sectorId>` for the failed sector(s).
|
||||
The output of `lotus-miner sectors status --log <sectorId>` for the failed sector(s).
|
||||
|
||||
**Lotus storage miner logs**
|
||||
**Lotus miner logs**
|
||||
|
||||
Please go through the logs of your storage miner, and include screenshots of any error-like messages you find.
|
||||
Please go through the logs of your miner, and include screenshots of any error-like messages you find.
|
||||
|
||||
Alternatively please upload full log files and share a link here
|
||||
|
||||
**Lotus miner diagnostic info**
|
||||
|
||||
Please collect the following diagnostic information, and share a link here
|
||||
|
||||
* lotus-miner diagnostic info `lotus-miner info all > allinfo`
|
||||
|
||||
** Code modifications **
|
||||
|
||||
If you have modified parts of lotus, please describe which areas were modified,
|
||||
and the scope of those modifications
|
||||
|
||||
**Version**
|
||||
|
||||
The output of `./lotus --version`.
|
||||
The output of `lotus --version`.
|
||||
|
||||
@@ -0,0 +1,248 @@
|
||||
###
|
||||
### Special magic GitHub labels
|
||||
### https://help.github.com/en/github/building-a-strong-community/encouraging-helpful-contributions-to-your-project-with-labels
|
||||
#
|
||||
- name: "good first issue"
|
||||
color: 7057ff
|
||||
description: "Good for newcomers"
|
||||
- name: "help wanted"
|
||||
color: 008672
|
||||
description: "Extra attention is needed"
|
||||
|
||||
###
|
||||
### Goals
|
||||
#
|
||||
- name: goal/incentives
|
||||
color: ff004d
|
||||
description: "Incentinet"
|
||||
|
||||
###
|
||||
### Areas
|
||||
#
|
||||
- name: area/ux
|
||||
color: 00A4E0
|
||||
description: "Area: UX"
|
||||
- name: area/chain/vm
|
||||
color: 00A4E2
|
||||
description: "Area: Chain/VM"
|
||||
- name: area/chain/sync
|
||||
color: 00A4E4
|
||||
description: "Area: Chain/Sync"
|
||||
- name: area/chain/misc
|
||||
color: 00A4E6
|
||||
description: "Area: Chain/Misc"
|
||||
- name: area/markets
|
||||
color: 00A4E8
|
||||
description: "Area: Markets"
|
||||
- name: area/sealing/fsm
|
||||
color: 0bb1ed
|
||||
description: "Area: Sealing/FSM"
|
||||
- name: area/sealing/storage
|
||||
color: 0EB4F0
|
||||
description: "Area: Sealing/Storage"
|
||||
- name: area/proving
|
||||
color: 0EB4F0
|
||||
description: "Area: Proving"
|
||||
- name: area/mining
|
||||
color: 10B6F2
|
||||
description: "Area: Mining"
|
||||
- name: area/client/storage
|
||||
color: 13B9F5
|
||||
description: "Area: Client/Storage"
|
||||
- name: area/client/retrieval
|
||||
color: 15BBF7
|
||||
description: "Area: Client/Retrieval"
|
||||
- name: area/wallet
|
||||
color: 15BBF7
|
||||
description: "Area: Wallet"
|
||||
- name: area/payment-channel
|
||||
color: ff6767
|
||||
description: "Area: Payment Channel"
|
||||
- name: area/multisig
|
||||
color: fff0ff
|
||||
description: "Area: Multisig"
|
||||
- name: area/networking
|
||||
color: 273f8a
|
||||
description: "Area: Networking"
|
||||
|
||||
###
|
||||
### Kinds
|
||||
#
|
||||
- name: kind/bug
|
||||
color: c92712
|
||||
description: "Kind: Bug"
|
||||
- name: kind/chore
|
||||
color: fcf0b5
|
||||
description: "Kind: Chore"
|
||||
- name: kind/feature
|
||||
color: FFF3B8
|
||||
description: "Kind: Feature"
|
||||
- name: kind/improvement
|
||||
color: FFF5BA
|
||||
description: "Kind: Improvement"
|
||||
- name: kind/test
|
||||
color: FFF8BD
|
||||
description: "Kind: Test"
|
||||
- name: kind/question
|
||||
color: FFFDC2
|
||||
description: "Kind: Question"
|
||||
- name: kind/enhancement
|
||||
color: FFFFC5
|
||||
description: "Kind: Enhancement"
|
||||
- name: kind/discussion
|
||||
color: FFFFC7
|
||||
description: "Kind: Discussion"
|
||||
|
||||
###
|
||||
### Difficulties
|
||||
#
|
||||
- name: dif/trivial
|
||||
color: b2b7ff
|
||||
description: "Can be confidently tackled by newcomers, who are widely unfamiliar with lotus"
|
||||
- name: dif/easy
|
||||
color: 7886d7
|
||||
description: "An existing lotus user should be able to pick this up"
|
||||
- name: dif/medium
|
||||
color: 6574cd
|
||||
description: "Prior development experience with lotus is likely helpful"
|
||||
- name: dif/hard
|
||||
color: 5661b3
|
||||
description: "Suggests that having worked on the specific component affected by this issue is important"
|
||||
- name: dif/expert
|
||||
color: 2f365f
|
||||
description: "Requires extensive knowledge of the history, implications, ramifications of the issue"
|
||||
|
||||
###
|
||||
### Efforts
|
||||
#
|
||||
- name: effort/minutes
|
||||
color: e8fffe
|
||||
description: "Effort: Minutes"
|
||||
- name: effort/hours
|
||||
color: a0f0ed
|
||||
description: "Effort: Hours"
|
||||
- name: effort/day
|
||||
color: 64d5ca
|
||||
description: "Effort: One Day"
|
||||
- name: effort/days
|
||||
color: 4dc0b5
|
||||
description: "Effort: Multiple Days"
|
||||
- name: effort/week
|
||||
color: 38a89d
|
||||
description: "Effort: One Week"
|
||||
- name: effort/weeks
|
||||
color: 20504f
|
||||
description: "Effort: Multiple Weeks"
|
||||
|
||||
###
|
||||
### Impacts
|
||||
#
|
||||
- name: impact/regression
|
||||
color: f1f5f8
|
||||
description: "Impact: Regression"
|
||||
- name: impact/api-breakage
|
||||
color: ECF0F3
|
||||
description: "Impact: API Breakage"
|
||||
- name: impact/quality
|
||||
color: E7EBEE
|
||||
description: "Impact: Quality"
|
||||
- name: impact/dx
|
||||
color: E2E6E9
|
||||
description: "Impact: Developer Experience"
|
||||
- name: impact/test-flakiness
|
||||
color: DDE1E4
|
||||
description: "Impact: Test Flakiness"
|
||||
- name: impact/consensus
|
||||
color: b20014
|
||||
description: "Impact: Consensus"
|
||||
|
||||
###
|
||||
### Topics
|
||||
#
|
||||
- name: topic/interoperability
|
||||
color: bf0f73
|
||||
description: "Topic: Interoperability"
|
||||
- name: topic/specs
|
||||
color: CC1C80
|
||||
description: "Topic: Specs"
|
||||
- name: topic/docs
|
||||
color: D9298D
|
||||
description: "Topic: Documentation"
|
||||
- name: topic/architecture
|
||||
color: E53599
|
||||
description: "Topic: Architecture"
|
||||
|
||||
###
|
||||
### Priorities
|
||||
###
|
||||
- name: P0
|
||||
color: dd362a
|
||||
description: "P0: Critical Blocker"
|
||||
- name: P1
|
||||
color: ce8048
|
||||
description: "P1: Must be resolved"
|
||||
- name: P2
|
||||
color: dbd81a
|
||||
description: "P2: Should be resolved"
|
||||
- name: P3
|
||||
color: 9fea8f
|
||||
description: "P3: Might get resolved"
|
||||
|
||||
###
|
||||
### Hints
|
||||
#
|
||||
#- name: hint/good-first-issue
|
||||
# color: 7057ff
|
||||
# description: "Hint: Good First Issue"
|
||||
#- name: hint/help-wanted
|
||||
# color: 008672
|
||||
# description: "Hint: Help Wanted"
|
||||
- name: hint/needs-decision
|
||||
color: 33B9A5
|
||||
description: "Hint: Needs Decision"
|
||||
- name: hint/needs-triage
|
||||
color: 1AA08C
|
||||
description: "Hint: Needs Triage"
|
||||
- name: hint/needs-analysis
|
||||
color: 26AC98
|
||||
description: "Hint: Needs Analysis"
|
||||
- name: hint/needs-author-input
|
||||
color: 33B9A5
|
||||
description: "Hint: Needs Author Input"
|
||||
- name: hint/needs-team-input
|
||||
color: 40C6B2
|
||||
description: "Hint: Needs Team Input"
|
||||
- name: hint/needs-community-input
|
||||
color: 4DD3BF
|
||||
description: "Hint: Needs Community Input"
|
||||
- name: hint/needs-review
|
||||
color: 5AE0CC
|
||||
description: "Hint: Needs Review"
|
||||
|
||||
###
|
||||
### Statuses
|
||||
#
|
||||
- name: status/done
|
||||
color: edb3a6
|
||||
description: "Status: Done"
|
||||
- name: status/deferred
|
||||
color: E0A699
|
||||
description: "Status: Deferred"
|
||||
- name: status/in-progress
|
||||
color: D49A8D
|
||||
description: "Status: In Progress"
|
||||
- name: status/blocked
|
||||
color: C78D80
|
||||
description: "Status: Blocked"
|
||||
- name: status/inactive
|
||||
color: BA8073
|
||||
description: "Status: Inactive"
|
||||
- name: status/waiting
|
||||
color: AD7366
|
||||
description: "Status: Waiting"
|
||||
- name: status/rotten
|
||||
color: 7A4033
|
||||
description: "Status: Rotten"
|
||||
- name: status/discarded
|
||||
color: 6D3326
|
||||
description: "Status: Discarded / Won't fix"
|
||||
@@ -0,0 +1,17 @@
|
||||
|
||||
name: Label syncer
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '.github/labels.yml'
|
||||
branches:
|
||||
- master
|
||||
jobs:
|
||||
build:
|
||||
name: Sync labels
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@1.0.0
|
||||
- uses: micnncim/action-label-syncer@v1.0.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
+9
-8
@@ -1,19 +1,21 @@
|
||||
/lotus
|
||||
/lotus-storage-miner
|
||||
/lotus-seal-worker
|
||||
/lotus-miner
|
||||
/lotus-worker
|
||||
/lotus-seed
|
||||
/lotus-health
|
||||
/lotus-chainwatch
|
||||
/lotus-shed
|
||||
/pond
|
||||
/townhall
|
||||
/fountain
|
||||
/stats
|
||||
/bench
|
||||
/lotus-pond
|
||||
/lotus-townhall
|
||||
/lotus-fountain
|
||||
/lotus-stats
|
||||
/lotus-bench
|
||||
/bench.json
|
||||
/lotuspond/front/node_modules
|
||||
/lotuspond/front/build
|
||||
/cmd/lotus-townhall/townhall/node_modules
|
||||
/cmd/lotus-townhall/townhall/build
|
||||
/cmd/lotus-townhall/townhall/package-lock.json
|
||||
extern/filecoin-ffi/rust/target
|
||||
**/*.a
|
||||
**/*.pc
|
||||
@@ -24,7 +26,6 @@ build/paramfetch.sh
|
||||
/vendor
|
||||
/blocks.dot
|
||||
/blocks.svg
|
||||
/chainwatch
|
||||
/chainwatch.db
|
||||
/bundle
|
||||
/darwin
|
||||
|
||||
@@ -5,3 +5,6 @@
|
||||
[submodule "extern/serialization-vectors"]
|
||||
path = extern/serialization-vectors
|
||||
url = https://github.com/filecoin-project/serialization-vectors
|
||||
[submodule "extern/test-vectors"]
|
||||
path = extern/test-vectors
|
||||
url = https://github.com/filecoin-project/test-vectors.git
|
||||
|
||||
@@ -23,6 +23,14 @@ issues:
|
||||
- "Potential file inclusion via variable"
|
||||
- "should have( a package)? comment"
|
||||
- "Error return value of `logging.SetLogLevel` is not checked"
|
||||
- "comment on exported"
|
||||
- "(func|method) \\w+ should be \\w+"
|
||||
- "(type|var|struct field|(method|func) parameter) `\\w+` should be `\\w+`"
|
||||
- "(G306|G301|G307|G108|G302|G204|G104)"
|
||||
- "don't use ALL_CAPS in Go names"
|
||||
- "string .* has .* occurrences, make it a constant"
|
||||
- "a blank import should be only in a main or test package, or have a comment justifying it"
|
||||
- "package comment should be of the form"
|
||||
|
||||
exclude-use-default: false
|
||||
exclude-rules:
|
||||
@@ -46,6 +54,19 @@ issues:
|
||||
linters:
|
||||
- gosec
|
||||
|
||||
- path: chain/vectors/gen/.*
|
||||
linters:
|
||||
- gosec
|
||||
|
||||
- path: cmd/lotus-bench/.*
|
||||
linters:
|
||||
- gosec
|
||||
|
||||
- path: api/test/.*
|
||||
text: "context.Context should be the first parameter"
|
||||
linters:
|
||||
- golint
|
||||
|
||||
linters-settings:
|
||||
goconst:
|
||||
min-occurrences: 6
|
||||
|
||||
+450
-4
@@ -1,7 +1,453 @@
|
||||
# lotus changelog
|
||||
# Lotus changelog
|
||||
|
||||
## 0.1.0 / 2019-12-11
|
||||
# 0.7.0 / 2020-09-10
|
||||
|
||||
We are very excited to release **lotus** 0.1.0. This is our testnet release. To install lotus and join the testnet, please visit [docs.lotu.sh](docs.lotu.sh). Please file bug reports as [issues](https://github.com/filecoin-project/lotus/issues).
|
||||
This consensus-breaking release of Lotus is designed to test a network upgrade on the space race testnet. The changes that break consensus are:
|
||||
|
||||
A huge thank you to all contributors for this testnet release!
|
||||
- Upgrading the Drand network used from the test Drand network to the League of Entropy main drand network. This is the same Drand network that will be used in the Filecoin mainnet.
|
||||
- Upgrading to specs-actors v0.9.8, which adds a new method to the Multisig actor.
|
||||
|
||||
## Changes
|
||||
|
||||
#### Core Lotus
|
||||
|
||||
- Fix IsAncestorOf (https://github.com/filecoin-project/lotus/pull/3717)
|
||||
- Update to specs-actors v0.9.8 (https://github.com/filecoin-project/lotus/pull/3725)
|
||||
- Increase chain throughput by 20% (https://github.com/filecoin-project/lotus/pull/3732)
|
||||
- Updare to go-libp2p-pubsub `master` (https://github.com/filecoin-project/lotus/pull/3735)
|
||||
- Drand upgrade (https://github.com/filecoin-project/lotus/pull/3670)
|
||||
- Multisig API additions (https://github.com/filecoin-project/lotus/pull/3590)
|
||||
|
||||
#### Storage Miner
|
||||
|
||||
- Increase the number of times precommit2 is attempted before moving back to precommit1 (https://github.com/filecoin-project/lotus/pull/3720)
|
||||
|
||||
#### Message pool
|
||||
|
||||
- Relax mpool add strictness checks for local pushes (https://github.com/filecoin-project/lotus/pull/3724)
|
||||
|
||||
|
||||
#### Maintenance
|
||||
|
||||
- Fix devnets (https://github.com/filecoin-project/lotus/pull/3712)
|
||||
- Fix(chainwatch): compare prev miner with cur miner (https://github.com/filecoin-project/lotus/pull/3715)
|
||||
- CI: fix statediff build; make optional (https://github.com/filecoin-project/lotus/pull/3729)
|
||||
- Feat: Chaos abort (https://github.com/filecoin-project/lotus/pull/3733)
|
||||
|
||||
## Contributors
|
||||
|
||||
The following contributors had commits go into this release.
|
||||
We are grateful for every contribution!
|
||||
|
||||
| Contributor | Commits | Lines ± |
|
||||
|--------------------|---------|---------------|
|
||||
| arajasek | 28 | +1144/-239 |
|
||||
| Kubuxu | 19 | +452/-261 |
|
||||
| whyrusleeping | 13 | +456/-87 |
|
||||
| vyzo | 11 | +318/-20 |
|
||||
| raulk | 10 | +1289/-350 |
|
||||
| magik6k | 6 | +188/-55 |
|
||||
| dirkmc | 3 | +31/-8 |
|
||||
| alanshaw | 3 | +176/-37 |
|
||||
| Stebalien | 2 | +9/-12 |
|
||||
| lanzafame | 1 | +1/-1 |
|
||||
| frrist | 1 | +1/-1 |
|
||||
| mishmosh | 1 | +1/-1 |
|
||||
| nonsense | 1 | +1/-0 |
|
||||
|
||||
# 0.6.2 / 2020-09-09
|
||||
|
||||
This release introduces some critical fixes to message selection and gas estimation logic. It also adds the ability for nodes to mark a certain tipset as checkpointed, as well as various minor improvements and bugfixes.
|
||||
|
||||
## Changes
|
||||
|
||||
#### Messagepool
|
||||
|
||||
- Warn when optimal selection fails to pack a block and we fall back to random selection (https://github.com/filecoin-project/lotus/pull/3708)
|
||||
- Add basic command for printing gas performance of messages in the mpool (https://github.com/filecoin-project/lotus/pull/3701)
|
||||
- Adjust optimal selection to always try to fill blocks (https://github.com/filecoin-project/lotus/pull/3685)
|
||||
- Fix very minor bug in repub baseFeeLowerBound (https://github.com/filecoin-project/lotus/pull/3663)
|
||||
- Add an auto flag to mpool replace (https://github.com/filecoin-project/lotus/pull/3676)
|
||||
- Fix mpool optimal selection packing failure (https://github.com/filecoin-project/lotus/pull/3698)
|
||||
|
||||
#### Core Lotus
|
||||
|
||||
- Don't use latency as initital estimate for blocksync (https://github.com/filecoin-project/lotus/pull/3648)
|
||||
- Add niceSleep 1 second when drand errors (https://github.com/filecoin-project/lotus/pull/3664)
|
||||
- Fix isChainNearSync check in block validator (https://github.com/filecoin-project/lotus/pull/3650)
|
||||
- Add peer to peer manager before fetching the tipset (https://github.com/filecoin-project/lotus/pull/3667)
|
||||
- Add StageFetchingMessages to sync status (https://github.com/filecoin-project/lotus/pull/3668)
|
||||
- Pass tipset through upgrade logic (https://github.com/filecoin-project/lotus/pull/3673)
|
||||
- Allow nodes to mark tipsets as checkpointed (https://github.com/filecoin-project/lotus/pull/3680)
|
||||
- Remove hard-coded late-fee in window PoSt (https://github.com/filecoin-project/lotus/pull/3702)
|
||||
- Gas: Fix median calc (https://github.com/filecoin-project/lotus/pull/3686)
|
||||
|
||||
#### Storage
|
||||
|
||||
- Storage manager: bail out with an error if unsealed cid is undefined (https://github.com/filecoin-project/lotus/pull/3655)
|
||||
- Storage: return true from Sealer.ReadPiece() on success (https://github.com/filecoin-project/lotus/pull/3657)
|
||||
|
||||
#### Maintenance
|
||||
|
||||
- Resolve lotus, test-vectors, statediff dependency cycle (https://github.com/filecoin-project/lotus/pull/3688)
|
||||
- Paych: add docs on how to use paych status (https://github.com/filecoin-project/lotus/pull/3690)
|
||||
- Initial CODEOWNERS (https://github.com/filecoin-project/lotus/pull/3691)
|
||||
|
||||
# 0.6.1 / 2020-09-08
|
||||
|
||||
This optional release introduces a minor improvement to the sync process, ensuring nodes don't fall behind and then resync.
|
||||
|
||||
## Changes
|
||||
|
||||
- Update `test-vectors` (https://github.com/filecoin-project/lotus/pull/3645)
|
||||
- Revert "only subscribe to pubsub topics once we are synced" (https://github.com/filecoin-project/lotus/pull/3643)
|
||||
|
||||
# 0.6.0 / 2020-09-07
|
||||
|
||||
This consensus-breaking release of Lotus is designed to test a network upgrade on the space race testnet. The changes that break consensus are:
|
||||
|
||||
- Tweaking of some cryptoecon parameters in specs-actors 0.9.7 (https://github.com/filecoin-project/specs-actors/releases/tag/v0.9.7)
|
||||
- Rebalancing FIL distribution to make testnet FIL scarce, which prevents base fee spikes and sets better expectations for mainnet
|
||||
|
||||
This release also introduces many improvements to Lotus! Among them are a new version of go-fil-markets that supports non-blocking retrieval, various spam reduction measures in the messagepool and p2p logic, and UX improvements to payment channels, dealmaking, and state inspection.
|
||||
|
||||
## Changes
|
||||
|
||||
#### Core Lotus and dependencies
|
||||
|
||||
- Implement faucet funds reallocation logic (https://github.com/filecoin-project/lotus/pull/3632)
|
||||
- Network upgrade: Upgrade to correct fork threshold (https://github.com/filecoin-project/lotus/pull/3628)
|
||||
- Update to specs 0.9.7 and markets 0.6.0 (https://github.com/filecoin-project/lotus/pull/3627)
|
||||
- Network upgrade: Perform base fee tamping (https://github.com/filecoin-project/lotus/pull/3623)
|
||||
- Chain events: if cache best() is nil, return chain head (https://github.com/filecoin-project/lotus/pull/3611)
|
||||
- Update to specs actors v0.9.6 (https://github.com/filecoin-project/lotus/pull/3603)
|
||||
|
||||
#### Messagepool
|
||||
|
||||
- Temporarily allow negative chains (https://github.com/filecoin-project/lotus/pull/3625)
|
||||
- Improve publish/republish logic (https://github.com/filecoin-project/lotus/pull/3592)
|
||||
- Fix selection bug; priority messages were not included if other chains were negative (https://github.com/filecoin-project/lotus/pull/3580)
|
||||
- Add defensive check for minimum GasFeeCap for inclusion within the next 20 blocks (https://github.com/filecoin-project/lotus/pull/3579)
|
||||
- Add additional info about gas premium (https://github.com/filecoin-project/lotus/pull/3578)
|
||||
- Fix GasPremium capping logic (https://github.com/filecoin-project/lotus/pull/3552)
|
||||
|
||||
#### Payment channels
|
||||
|
||||
- Get available funds by address or by from/to (https://github.com/filecoin-project/lotus/pull/3547)
|
||||
- Create `lotus paych status` command (https://github.com/filecoin-project/lotus/pull/3523)
|
||||
- Rename CLI command from "paych get" to "paych add-funds" (https://github.com/filecoin-project/lotus/pull/3520)
|
||||
|
||||
#### Peer-to-peer
|
||||
|
||||
- Only subscribe to pubsub topics once we are synced (https://github.com/filecoin-project/lotus/pull/3602)
|
||||
- Reduce mpool add failure log spam (https://github.com/filecoin-project/lotus/pull/3562)
|
||||
- Republish messages even if the chains have negative performance(https://github.com/filecoin-project/lotus/pull/3557)
|
||||
- Adjust gossipsub gossip factor (https://github.com/filecoin-project/lotus/pull/3556)
|
||||
- Integrate pubsub Random Early Drop (https://github.com/filecoin-project/lotus/pull/3518)
|
||||
|
||||
#### Miscellaneous
|
||||
|
||||
- Fix panic in OnDealExpiredSlashed (https://github.com/filecoin-project/lotus/pull/3553)
|
||||
- Robustify state manager against holes in actor method numbers (https://github.com/filecoin-project/lotus/pull/3538)
|
||||
|
||||
#### UX
|
||||
|
||||
- VM: Fix an error message (https://github.com/filecoin-project/lotus/pull/3608)
|
||||
- Documentation: Batch replacement,update lotus-storage-miner to lotus-miner (https://github.com/filecoin-project/lotus/pull/3571)
|
||||
- CLI: Robust actor lookup (https://github.com/filecoin-project/lotus/pull/3535)
|
||||
- Add agent flag to net peers (https://github.com/filecoin-project/lotus/pull/3534)
|
||||
- Add watch option to storage-deals list (https://github.com/filecoin-project/lotus/pull/3527)
|
||||
|
||||
#### Testing & tooling
|
||||
|
||||
- Decommission chain-validation (https://github.com/filecoin-project/lotus/pull/3606)
|
||||
- Metrics: add expected height metric (https://github.com/filecoin-project/lotus/pull/3586)
|
||||
- PCR: Use current tipset during refund (https://github.com/filecoin-project/lotus/pull/3570)
|
||||
- Lotus-shed: Add math command (https://github.com/filecoin-project/lotus/pull/3568)
|
||||
- PCR: Add tipset aggergation (https://github.com/filecoin-project/lotus/pull/3565)- Fix broken paych tests (https://github.com/filecoin-project/lotus/pull/3551)
|
||||
- Make chain export ~1000x times faster (https://github.com/filecoin-project/lotus/pull/3533)
|
||||
- Chainwatch: Stop SyncIncomingBlocks from leaking into chainwatch processing; No panics during processing (https://github.com/filecoin-project/lotus/pull/3526)
|
||||
- Conformance: various changes (https://github.com/filecoin-project/lotus/pull/3521)
|
||||
|
||||
# 0.5.10 / 2020-09-03
|
||||
|
||||
This patch includes a crucial fix to the message pool selection logic, strongly disfavouring messages that might cause a miner penalty.
|
||||
|
||||
## Changes
|
||||
|
||||
- Fix calculation of GasReward in messagepool (https://github.com/filecoin-project/lotus/pull/3528)
|
||||
|
||||
# 0.5.9 / 2020-09-03
|
||||
|
||||
This patch includes a hotfix to the `GasEstimateFeeCap` method, capping the estimated fee to a reasonable level by default.
|
||||
|
||||
## Changes
|
||||
|
||||
- Added target height to sync wait (https://github.com/filecoin-project/lotus/pull/3502)
|
||||
- Disable codecov annotations (https://github.com/filecoin-project/lotus/pull/3514)
|
||||
- Cap fees to reasonable level by default (https://github.com/filecoin-project/lotus/pull/3516)
|
||||
- Add APIs and command to inspect bandwidth usage (https://github.com/filecoin-project/lotus/pull/3497)
|
||||
- Track expected nonce in mpool, ignore messages with large nonce gaps (https://github.com/filecoin-project/lotus/pull/3450)
|
||||
|
||||
# 0.5.8 / 2020-09-02
|
||||
|
||||
This patch includes some bugfixes to the sector sealing process, and updates go-fil-markets. It also improves the performance of blocksync, adds a method to export chain state trees, and improves chainwatch.
|
||||
|
||||
## Changes
|
||||
|
||||
- Upgrade markets to v0.5.9 (https://github.com/filecoin-project/lotus/pull/3496)
|
||||
- Improve blocksync to load fewer messages: (https://github.com/filecoin-project/lotus/pull/3494)
|
||||
- Fix a panic in the ffi-wrapper's `ReadPiece` (https://github.com/filecoin-project/lotus/pull/3492/files)
|
||||
- Fix a deadlock in the sealing scheduler (https://github.com/filecoin-project/lotus/pull/3489)
|
||||
- Add test vectors for tipset tests (https://github.com/filecoin-project/lotus/pull/3485/files)
|
||||
- Improve the advance-block debug command (https://github.com/filecoin-project/lotus/pull/3476)
|
||||
- Add toggle for message processing to Lotus PCR (https://github.com/filecoin-project/lotus/pull/3470)
|
||||
- Allow exporting recent chain state trees (https://github.com/filecoin-project/lotus/pull/3463)
|
||||
- Remove height from chain rand (https://github.com/filecoin-project/lotus/pull/3458)
|
||||
- Disable GC on chain badger datastore (https://github.com/filecoin-project/lotus/pull/3457)
|
||||
- Account for `GasPremium` in `GasEstimateFeeCap` (https://github.com/filecoin-project/lotus/pull/3456)
|
||||
- Update go-libp2p-pubsub to `master` (https://github.com/filecoin-project/lotus/pull/3455)
|
||||
- Chainwatch improvements (https://github.com/filecoin-project/lotus/pull/3442)
|
||||
|
||||
# 0.5.7 / 2020-08-31
|
||||
|
||||
This patch release includes some bugfixes and enhancements to the sector lifecycle and message pool logic.
|
||||
|
||||
## Changes
|
||||
|
||||
- Rebuild unsealed infos on miner restart (https://github.com/filecoin-project/lotus/pull/3401)
|
||||
- CLI to attach storage paths to workers (https://github.com/filecoin-project/lotus/pull/3405)
|
||||
- Do not select negative performing message chains for inclusion (https://github.com/filecoin-project/lotus/pull/3392)
|
||||
- Remove a redundant error-check (https://github.com/filecoin-project/lotus/pull/3421)
|
||||
- Correctly move unsealed sectors in `FinalizeSectors` (https://github.com/filecoin-project/lotus/pull/3424)
|
||||
- Improve worker selection logic (https://github.com/filecoin-project/lotus/pull/3425)
|
||||
- Don't use context to close bitswap (https://github.com/filecoin-project/lotus/pull/3430)
|
||||
- Correctly estimate gas premium when there is only one message on chain (https://github.com/filecoin-project/lotus/pull/3428)
|
||||
|
||||
# 0.5.6 / 2020-08-29
|
||||
|
||||
Hotfix release that fixes a panic in the sealing scheduler (https://github.com/filecoin-project/lotus/pull/3389).
|
||||
|
||||
# 0.5.5
|
||||
|
||||
This patch release introduces a large number of improvements to the sealing process.
|
||||
It also updates go-fil-markets to
|
||||
[version 0.5.8](https://github.com/filecoin-project/go-fil-markets/releases/tag/v0.5.8),
|
||||
and go-libp2p-pubsub to [v0.3.5](https://github.com/libp2p/go-libp2p-pubsub/releases/tag/v0.3.5).
|
||||
|
||||
#### Downstream upgrades
|
||||
|
||||
- Upgrades markets to v0.5.8 (https://github.com/filecoin-project/lotus/pull/3384)
|
||||
- Upgrades go-libp2p-pubsub to v0.3.5 (https://github.com/filecoin-project/lotus/pull/3305)
|
||||
|
||||
#### Sector sealing
|
||||
|
||||
- The following improvements were introduced in https://github.com/filecoin-project/lotus/pull/3350.
|
||||
|
||||
- Allow `lotus-miner sectors remove` to remove a sector in any state.
|
||||
- Create a separate state in the storage FSM dedicated to submitting the Commit message.
|
||||
- Recovery for when the Deal IDs of deals in a sector get changed in a reorg.
|
||||
- Auto-retry sending Precommit and Commit messages if they run out of gas
|
||||
- Auto-retry sector remove tasks when they fail
|
||||
- Compact worker windows, and allow their tasks to be executed in any order
|
||||
|
||||
- Don't simply skip PoSt for bad sectors (https://github.com/filecoin-project/lotus/pull/3323)
|
||||
|
||||
#### Message Pool
|
||||
|
||||
- Spam Protection: Track required funds for pending messages (https://github.com/filecoin-project/lotus/pull/3313)
|
||||
|
||||
#### Chainwatch
|
||||
|
||||
- Add more power and reward metrics (https://github.com/filecoin-project/lotus/pull/3367)
|
||||
- Fix raciness in sector deal table (https://github.com/filecoin-project/lotus/pull/3275)
|
||||
- Parallelize miner processing (https://github.com/filecoin-project/lotus/pull/3380)
|
||||
- Accept Lotus API and token (https://github.com/filecoin-project/lotus/pull/3337)
|
||||
|
||||
# 0.5.4
|
||||
|
||||
A patch release, containing a few nice bugfixes and improvements:
|
||||
|
||||
- Fix parsing of peer ID in `lotus-miner actor set-peer-id` (@whyrusleeping)
|
||||
- Update dependencies, fixing several bugs (@Stebalien)
|
||||
- Fix remaining linter warnings (@Stebalien)
|
||||
- Use safe string truncation (@Ingar)
|
||||
- Allow tweaking of blocksync message window size (@whyrusleeping)
|
||||
- Add some additional gas stats to metrics (@Kubuxu)
|
||||
- Fix an edge case bug in message selection, add many tests (@vyzo)
|
||||
|
||||
# 0.5.3
|
||||
|
||||
Yet another hotfix release.
|
||||
A lesson for readers, having people who have been awake for 12+ hours review
|
||||
your hotfix PR is not a good idea. Find someone who has enough slept recently
|
||||
enough to give you good code review, otherwise you'll end up quickly bumping
|
||||
versions again.
|
||||
|
||||
- Fixed a bug in the mempool that was introduced in v0.5.2
|
||||
|
||||
# 0.5.2 / 2020-08-24
|
||||
|
||||
This is a hotfix release.
|
||||
|
||||
- Fix message selection to not include messages that are invalid for block
|
||||
inclusion.
|
||||
- Improve SelectMessage handling of the case where the message pools tipset
|
||||
differs from our mining base.
|
||||
|
||||
# 0.5.1 / 2020-08-24
|
||||
|
||||
The Space Race release!
|
||||
This release contains the genesis car file and bootstrap peers for the space
|
||||
race network.
|
||||
|
||||
Additionally, we included two small fixes to genesis creation:
|
||||
- Randomize ticket value in genesis generation
|
||||
- Correctly set t099 (burnt funds actor) to have valid account actor state
|
||||
|
||||
# 0.5.0 / 2020-08-20
|
||||
|
||||
This version of Lotus will be used for the incentivized testnet Space Race competition,
|
||||
and can be considered mainnet-ready code. It includes some protocol
|
||||
changes, upgrades of core dependencies, and various bugfixes and UX/performance improvements.
|
||||
|
||||
## Highlights
|
||||
|
||||
Among the highlights included in this release are:
|
||||
|
||||
- Gas changes: We implemented EIP-1559 and introduced real gas values.
|
||||
- Deal-making: We now support "Committed Capacity" sectors, "fast-retrieval" deals,
|
||||
and the packing of multiple deals into a single sector.
|
||||
- Renamed features: We renamed some of the binaries, environment variables, and default
|
||||
paths associated with a Lotus node.
|
||||
|
||||
### Gas changes
|
||||
|
||||
We made some significant changes to the mechanics of gas in this release.
|
||||
|
||||
#### Network fee
|
||||
|
||||
We implemented something similar to
|
||||
[Ethereum's EIP-1559](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md).
|
||||
The `Message` structure had three changes:
|
||||
- The `GasPrice` field has been removed
|
||||
- A new `GasFeeCap` field has been added, which controls the maximum cost
|
||||
the sender incurs for the message
|
||||
- A new `GasPremium` field has been added, which controls the reward a miner
|
||||
earns for including the message
|
||||
|
||||
A sender will never be charged more than `GasFeeCap * GasLimit`.
|
||||
A miner will typically earn `GasPremium * GasLimit` as a reward.
|
||||
|
||||
The `Blockheader` structure has one new field, called `ParentBaseFee`.
|
||||
Informally speaking,the `ParentBaseFee`
|
||||
is increased when blocks are densely packed with messages, and decreased otherwise.
|
||||
|
||||
The `ParentBaseFee` is used when calculating how much a sender burns when executing a message. _Burning_ simply refers to sending attoFIL to a dedicated, unreachable account.
|
||||
A message causes `ParentBaseFee * GasUsed` attoFIL to be burnt.
|
||||
|
||||
#### Real gas values
|
||||
|
||||
This release also includes our first "real" gas costs for primitive operations.
|
||||
The costs were designed to account for both the _time_ that message execution takes,
|
||||
as well as the _space_ a message adds to the state tree.
|
||||
|
||||
## Deal-making changes
|
||||
|
||||
There are three key changes to the deal-making process.
|
||||
|
||||
#### Committed Capacity sectors
|
||||
|
||||
Miners can now pledge "Committed Capacity" (CC) sectors, which are explicitly
|
||||
stated as containing junk data, and must not include any deals. Miners can do this
|
||||
to increase their storage power, and win block rewards from this pledged storage.
|
||||
|
||||
They can mark these sectors as "upgradable" with `lotus-miner sectors mark-for-upgrade`.
|
||||
If the miner receives and accepts one or more storage deals, the sector that includes
|
||||
those deals will _replace_ the CC sector. This is intended to maximize the amount of useful
|
||||
storage on the Filecoin network.
|
||||
|
||||
#### Fast-retrieval deals
|
||||
|
||||
Clients can now include a `fast-retrieval` flag when proposing deals with storage miners.
|
||||
If set to true, the miner will include an extra copy of the deal data. This
|
||||
data can be quickly served in a retrieval deal, since it will not need to be unsealed.
|
||||
|
||||
#### Multiple deals per sector
|
||||
|
||||
Miners can now pack multiple deals into a single sector, so long as all the deals
|
||||
fit into the sector capacity. This should increase the packing efficiency of miners.
|
||||
|
||||
### Renamed features
|
||||
|
||||
To improve the user experience, we updated several names to mainatin
|
||||
standard prefixing, and to better reflect the meaning of the features being referenced.
|
||||
|
||||
In particular, the Lotus miner binary is now called `lotus-miner`, the default
|
||||
path for miner data is now `~/.lotusminer`, and the environment variable
|
||||
that sets the path for miner data is now `$LOTUS_MINER_PATH`. A full list of renamed
|
||||
features can be found [here](https://github.com/filecoin-project/lotus/issues/2304).
|
||||
|
||||
## Changelog
|
||||
|
||||
#### Downstream upgrades
|
||||
- Upgrades markets to v0.5.6 (https://github.com/filecoin-project/lotus/pull/3058)
|
||||
- Upgrades specs-actors to v0.9.3 (https://github.com/filecoin-project/lotus/pull/3151)
|
||||
|
||||
#### Core protocol
|
||||
- Introduces gas values, replacing placeholders (https://github.com/filecoin-project/lotus/pull/2343)
|
||||
- Implements EIP-1559, introducing a network base fee, message gas fee cap, and message gas fee premium (https://github.com/filecoin-project/lotus/pull/2874)
|
||||
- Implements Poisson Sortition for elections (https://github.com/filecoin-project/lotus/pull/2084)
|
||||
|
||||
#### Deal-making lifecycle
|
||||
- Introduces "Committed Capacity" sectors (https://github.com/filecoin-project/lotus/pull/2220)
|
||||
- Introduces "fast-retrieval" flag for deals (https://github.com/filecoin-project/lotus/pull/2323
|
||||
- Supports packing multiple deals into one sector (https://github.com/filecoin-project/storage-fsm/pull/38)
|
||||
|
||||
#### Enhancements
|
||||
|
||||
- Optimized message pool selection logic (https://github.com/filecoin-project/lotus/pull/2838)
|
||||
- Window-based scheduling of sealing tasks (https://github.com/filecoin-project/sector-storage/pull/67)
|
||||
- Faster window PoSt (https://github.com/filecoin-project/lotus/pull/2209/files)
|
||||
- Refactors the payment channel manager (https://github.com/filecoin-project/lotus/pull/2640)
|
||||
- Refactors blocksync (https://github.com/filecoin-project/lotus/pull/2715/files)
|
||||
|
||||
#### UX
|
||||
|
||||
- Provide status updates for data-transfer (https://github.com/filecoin-project/lotus/pull/3162, https://github.com/filecoin-project/lotus/pull/3191)
|
||||
- Miners can customise asks (https://github.com/filecoin-project/lotus/pull/2046)
|
||||
- Miners can toggle auto-acceptance of deals (https://github.com/filecoin-project/lotus/pull/1994)
|
||||
- Miners can maintain a blocklist of piece CIDs (https://github.com/filecoin-project/lotus/pull/2069)
|
||||
|
||||
## Contributors
|
||||
|
||||
The following contributors had 10 or more commits go into this release.
|
||||
We are grateful for every contribution!
|
||||
|
||||
| Contributor | Commits | Lines ± |
|
||||
|--------------------|---------|---------------|
|
||||
| magik6k | 361 | +13197/-6136 |
|
||||
| Kubuxu | 227 | +5670/-2587 |
|
||||
| arajasek | 120 | +2916/-1264 |
|
||||
| whyrusleeping | 112 | +3979/-1089 |
|
||||
| vyzo | 99 | +3343/-1305 |
|
||||
| dirkmc | 68 | +8732/-3621 |
|
||||
| laser | 45 | +1489/-501 |
|
||||
| hannahhoward | 43 | +2654/-990 |
|
||||
| frrist | 37 | +6630/-4338 |
|
||||
| schomatis | 28 | +3016/-1368 |
|
||||
| placer14 | 27 | +824/-350 |
|
||||
| raulk | 25 | +28718/-29849 |
|
||||
| mrsmkl | 22 | +560/-368 |
|
||||
| travisperson | 18 | +1354/-314 |
|
||||
| nonsense | 16 | +2956/-2842 |
|
||||
| ingar | 13 | +331/-123 |
|
||||
| daviddias | 11 | +311/-11 |
|
||||
| Stebalien | 11 | +1204/-980 |
|
||||
| RobQuistNL | 10 | +69/-74 |
|
||||
|
||||
# 0.1.0 / 2019-12-11
|
||||
|
||||
We are very excited to release **lotus** 0.1.0. This is our testnet release. To install lotus and join the testnet, please visit [lotu.sh](lotu.sh). Please file bug reports as [issues](https://github.com/filecoin-project/lotus/issues).
|
||||
|
||||
A huge thank you to all contributors for this testnet release!
|
||||
|
||||
@@ -58,10 +58,10 @@ deps: $(BUILD_DEPS)
|
||||
.PHONY: deps
|
||||
|
||||
debug: GOFLAGS+=-tags=debug
|
||||
debug: lotus lotus-storage-miner lotus-seal-worker lotus-seed
|
||||
debug: lotus lotus-miner lotus-worker lotus-seed
|
||||
|
||||
2k: GOFLAGS+=-tags=2k
|
||||
2k: lotus lotus-storage-miner lotus-seal-worker lotus-seed
|
||||
2k: lotus lotus-miner lotus-worker lotus-seed
|
||||
|
||||
lotus: $(BUILD_DEPS)
|
||||
rm -f lotus
|
||||
@@ -71,19 +71,19 @@ lotus: $(BUILD_DEPS)
|
||||
.PHONY: lotus
|
||||
BINS+=lotus
|
||||
|
||||
lotus-storage-miner: $(BUILD_DEPS)
|
||||
rm -f lotus-storage-miner
|
||||
go build $(GOFLAGS) -o lotus-storage-miner ./cmd/lotus-storage-miner
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec lotus-storage-miner -i ./build
|
||||
.PHONY: lotus-storage-miner
|
||||
BINS+=lotus-storage-miner
|
||||
lotus-miner: $(BUILD_DEPS)
|
||||
rm -f lotus-miner
|
||||
go build $(GOFLAGS) -o lotus-miner ./cmd/lotus-storage-miner
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec lotus-miner -i ./build
|
||||
.PHONY: lotus-miner
|
||||
BINS+=lotus-miner
|
||||
|
||||
lotus-seal-worker: $(BUILD_DEPS)
|
||||
rm -f lotus-seal-worker
|
||||
go build $(GOFLAGS) -o lotus-seal-worker ./cmd/lotus-seal-worker
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec lotus-seal-worker -i ./build
|
||||
.PHONY: lotus-seal-worker
|
||||
BINS+=lotus-seal-worker
|
||||
lotus-worker: $(BUILD_DEPS)
|
||||
rm -f lotus-worker
|
||||
go build $(GOFLAGS) -o lotus-worker ./cmd/lotus-seal-worker
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec lotus-worker -i ./build
|
||||
.PHONY: lotus-worker
|
||||
BINS+=lotus-worker
|
||||
|
||||
lotus-shed: $(BUILD_DEPS)
|
||||
rm -f lotus-shed
|
||||
@@ -92,31 +92,22 @@ lotus-shed: $(BUILD_DEPS)
|
||||
.PHONY: lotus-shed
|
||||
BINS+=lotus-shed
|
||||
|
||||
build: lotus lotus-storage-miner lotus-seal-worker
|
||||
build: lotus lotus-miner lotus-worker
|
||||
@[[ $$(type -P "lotus") ]] && echo "Caution: you have \
|
||||
an existing lotus binary in your PATH. This may cause problems if you don't run 'sudo make install'" || true
|
||||
|
||||
.PHONY: build
|
||||
|
||||
install:
|
||||
install: install-daemon install-miner install-worker
|
||||
|
||||
install-daemon:
|
||||
install -C ./lotus /usr/local/bin/lotus
|
||||
install -C ./lotus-storage-miner /usr/local/bin/lotus-storage-miner
|
||||
install -C ./lotus-seal-worker /usr/local/bin/lotus-seal-worker
|
||||
|
||||
install-services: install
|
||||
mkdir -p /usr/local/lib/systemd/system
|
||||
mkdir -p /var/log/lotus
|
||||
install -C -m 0644 ./scripts/lotus-daemon.service /usr/local/lib/systemd/system/lotus-daemon.service
|
||||
install -C -m 0644 ./scripts/lotus-miner.service /usr/local/lib/systemd/system/lotus-miner.service
|
||||
systemctl daemon-reload
|
||||
@echo
|
||||
@echo "lotus-daemon and lotus-miner services installed. Don't forget to 'systemctl enable lotus-daemon|lotus-miner' for it to be enabled on startup."
|
||||
install-miner:
|
||||
install -C ./lotus-miner /usr/local/bin/lotus-miner
|
||||
|
||||
clean-services:
|
||||
rm -f /usr/local/lib/systemd/system/lotus-daemon.service
|
||||
rm -f /usr/local/lib/systemd/system/lotus-miner.service
|
||||
rm -f /usr/local/lib/systemd/system/chainwatch.service
|
||||
systemctl daemon-reload
|
||||
install-worker:
|
||||
install -C ./lotus-worker /usr/local/bin/lotus-worker
|
||||
|
||||
# TOOLS
|
||||
|
||||
@@ -134,83 +125,140 @@ benchmarks:
|
||||
@curl -X POST 'http://benchmark.kittyhawk.wtf/benchmark' -d '@bench.json' -u "${benchmark_http_cred}"
|
||||
.PHONY: benchmarks
|
||||
|
||||
pond: 2k
|
||||
go build -o pond ./lotuspond
|
||||
lotus-pond: 2k
|
||||
go build -o lotus-pond ./lotuspond
|
||||
(cd lotuspond/front && npm i && CI=false npm run build)
|
||||
.PHONY: pond
|
||||
BINS+=pond
|
||||
.PHONY: lotus-pond
|
||||
BINS+=lotus-pond
|
||||
|
||||
townhall:
|
||||
rm -f townhall
|
||||
go build -o townhall ./cmd/lotus-townhall
|
||||
lotus-townhall:
|
||||
rm -f lotus-townhall
|
||||
go build -o lotus-townhall ./cmd/lotus-townhall
|
||||
(cd ./cmd/lotus-townhall/townhall && npm i && npm run build)
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec townhall -i ./cmd/lotus-townhall -i ./build
|
||||
.PHONY: townhall
|
||||
BINS+=townhall
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec lotus-townhall -i ./cmd/lotus-townhall -i ./build
|
||||
.PHONY: lotus-townhall
|
||||
BINS+=lotus-townhall
|
||||
|
||||
fountain:
|
||||
rm -f fountain
|
||||
go build -o fountain ./cmd/lotus-fountain
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec fountain -i ./cmd/lotus-fountain -i ./build
|
||||
.PHONY: fountain
|
||||
BINS+=fountain
|
||||
lotus-fountain:
|
||||
rm -f lotus-fountain
|
||||
go build -o lotus-fountain ./cmd/lotus-fountain
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec lotus-fountain -i ./cmd/lotus-fountain -i ./build
|
||||
.PHONY: lotus-fountain
|
||||
BINS+=lotus-fountain
|
||||
|
||||
chainwatch:
|
||||
rm -f chainwatch
|
||||
go build -o chainwatch ./cmd/lotus-chainwatch
|
||||
.PHONY: chainwatch
|
||||
BINS+=chainwatch
|
||||
lotus-chainwatch:
|
||||
rm -f lotus-chainwatch
|
||||
go build $(GOFLAGS) -o lotus-chainwatch ./cmd/lotus-chainwatch
|
||||
.PHONY: lotus-chainwatch
|
||||
BINS+=lotus-chainwatch
|
||||
|
||||
install-chainwatch-service: chainwatch
|
||||
install -C ./chainwatch /usr/local/bin/chainwatch
|
||||
install -C -m 0644 ./scripts/chainwatch.service /usr/local/lib/systemd/system/chainwatch.service
|
||||
systemctl daemon-reload
|
||||
@echo
|
||||
@echo "chainwatch installed. Don't forget to 'systemctl enable chainwatch' for it to be enabled on startup."
|
||||
lotus-bench:
|
||||
rm -f lotus-bench
|
||||
go build -o lotus-bench ./cmd/lotus-bench
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec lotus-bench -i ./build
|
||||
.PHONY: lotus-bench
|
||||
BINS+=lotus-bench
|
||||
|
||||
bench:
|
||||
rm -f bench
|
||||
go build -o bench ./cmd/lotus-bench
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec bench -i ./build
|
||||
.PHONY: bench
|
||||
BINS+=bench
|
||||
lotus-stats:
|
||||
rm -f lotus-stats
|
||||
go build -o lotus-stats ./cmd/lotus-stats
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec lotus-stats -i ./build
|
||||
.PHONY: lotus-stats
|
||||
BINS+=lotus-stats
|
||||
|
||||
stats:
|
||||
rm -f stats
|
||||
go build -o stats ./tools/stats
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec stats -i ./build
|
||||
.PHONY: stats
|
||||
BINS+=stats
|
||||
lotus-pcr:
|
||||
rm -f lotus-pcr
|
||||
go build $(GOFLAGS) -o lotus-pcr ./cmd/lotus-pcr
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec lotus-pcr -i ./build
|
||||
.PHONY: lotus-pcr
|
||||
BINS+=lotus-pcr
|
||||
|
||||
health:
|
||||
lotus-health:
|
||||
rm -f lotus-health
|
||||
go build -o lotus-health ./cmd/lotus-health
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec lotus-health -i ./build
|
||||
|
||||
.PHONY: health
|
||||
BINS+=health
|
||||
.PHONY: lotus-health
|
||||
BINS+=lotus-health
|
||||
|
||||
testground:
|
||||
go build -tags testground -o /dev/null ./cmd/lotus
|
||||
|
||||
.PHONY: testground
|
||||
BINS+=testground
|
||||
|
||||
install-chainwatch: lotus-chainwatch
|
||||
install -C ./lotus-chainwatch /usr/local/bin/lotus-chainwatch
|
||||
|
||||
# SYSTEMD
|
||||
|
||||
install-daemon-service: install-daemon
|
||||
mkdir -p /etc/systemd/system
|
||||
mkdir -p /var/log/lotus
|
||||
install -C -m 0644 ./scripts/lotus-daemon.service /etc/systemd/system/lotus-daemon.service
|
||||
systemctl daemon-reload
|
||||
@echo
|
||||
@echo "lotus-daemon service installed. Don't forget to run 'sudo systemctl start lotus-daemon' to start it and 'sudo systemctl enable lotus-daemon' for it to be enabled on startup."
|
||||
|
||||
install-miner-service: install-miner install-daemon-service
|
||||
mkdir -p /etc/systemd/system
|
||||
mkdir -p /var/log/lotus
|
||||
install -C -m 0644 ./scripts/lotus-miner.service /etc/systemd/system/lotus-miner.service
|
||||
systemctl daemon-reload
|
||||
@echo
|
||||
@echo "lotus-miner service installed. Don't forget to run 'sudo systemctl start lotus-miner' to start it and 'sudo systemctl enable lotus-miner' for it to be enabled on startup."
|
||||
|
||||
install-chainwatch-service: install-chainwatch install-daemon-service
|
||||
mkdir -p /etc/systemd/system
|
||||
mkdir -p /var/log/lotus
|
||||
install -C -m 0644 ./scripts/lotus-chainwatch.service /etc/systemd/system/lotus-chainwatch.service
|
||||
systemctl daemon-reload
|
||||
@echo
|
||||
@echo "chainwatch service installed. Don't forget to run 'sudo systemctl start lotus-chainwatch' to start it and 'sudo systemctl enable lotus-chainwatch' for it to be enabled on startup."
|
||||
|
||||
install-main-services: install-miner-service
|
||||
|
||||
install-all-services: install-main-services install-chainwatch-service
|
||||
|
||||
install-services: install-main-services
|
||||
|
||||
clean-daemon-service: clean-miner-service clean-chainwatch-service
|
||||
-systemctl stop lotus-daemon
|
||||
-systemctl disable lotus-daemon
|
||||
rm -f /etc/systemd/system/lotus-daemon.service
|
||||
systemctl daemon-reload
|
||||
|
||||
clean-miner-service:
|
||||
-systemctl stop lotus-miner
|
||||
-systemctl disable lotus-miner
|
||||
rm -f /etc/systemd/system/lotus-miner.service
|
||||
systemctl daemon-reload
|
||||
|
||||
clean-chainwatch-service:
|
||||
-systemctl stop lotus-chainwatch
|
||||
-systemctl disable lotus-chainwatch
|
||||
rm -f /etc/systemd/system/lotus-chainwatch.service
|
||||
systemctl daemon-reload
|
||||
|
||||
clean-main-services: clean-daemon-service
|
||||
|
||||
clean-all-services: clean-main-services
|
||||
|
||||
clean-services: clean-all-services
|
||||
|
||||
# MISC
|
||||
|
||||
buildall: $(BINS)
|
||||
|
||||
completions:
|
||||
./scripts/make-completions.sh lotus
|
||||
./scripts/make-completions.sh lotus-storage-miner
|
||||
./scripts/make-completions.sh lotus-miner
|
||||
.PHONY: completions
|
||||
|
||||
install-completions:
|
||||
mkdir -p /usr/share/bash-completion/completions /usr/local/share/zsh/site-functions/
|
||||
install -C ./scripts/bash-completion/lotus /usr/share/bash-completion/completions/lotus
|
||||
install -C ./scripts/bash-completion/lotus-storage-miner /usr/share/bash-completion/completions/lotus-storage-miner
|
||||
install -C ./scripts/bash-completion/lotus-miner /usr/share/bash-completion/completions/lotus-miner
|
||||
install -C ./scripts/zsh-completion/lotus /usr/local/share/zsh/site-functions/_lotus
|
||||
install -C ./scripts/zsh-completion/lotus-storage-miner /usr/local/share/zsh/site-functions/_lotus-storage-miner
|
||||
install -C ./scripts/zsh-completion/lotus-miner /usr/local/share/zsh/site-functions/_lotus-miner
|
||||
|
||||
clean:
|
||||
rm -rf $(CLEAN) $(BINS)
|
||||
@@ -224,11 +272,15 @@ dist-clean:
|
||||
|
||||
type-gen:
|
||||
go run ./gen/main.go
|
||||
go generate ./...
|
||||
|
||||
method-gen:
|
||||
(cd ./lotuspond/front/src/chain && go run ./methodgen.go)
|
||||
|
||||
gen: type-gen method-gen
|
||||
|
||||
docsgen:
|
||||
go run ./api/docgen > documentation/en/api-methods.md
|
||||
|
||||
print-%:
|
||||
@echo $*=$($*)
|
||||
|
||||
@@ -1,12 +1,24 @@
|
||||

|
||||
<p align="center">
|
||||
<a href="https://lotu.sh/" title="Lotus Docs">
|
||||
<img src="documentation/images/lotus_logo_h.png" alt="Project Lotus Logo" width="244" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
# Project Lotus - 莲
|
||||
<h1 align="center">Project Lotus - 莲</h1>
|
||||
|
||||
Lotus is an implementation of the Filecoin Distributed Storage Network. For more details about Filecoin, check out the [Filecoin Spec](https://github.com/filecoin-project/specs).
|
||||
<p align="center">
|
||||
<a href="https://circleci.com/gh/filecoin-project/lotus"><img src="https://circleci.com/gh/filecoin-project/lotus.svg?style=svg"></a>
|
||||
<a href="https://codecov.io/gh/filecoin-project/lotus"><img src="https://codecov.io/gh/filecoin-project/lotus/branch/master/graph/badge.svg"></a>
|
||||
<a href="https://goreportcard.com/report/github.com/filecoin-project/lotus"><img src="https://goreportcard.com/badge/github.com/filecoin-project/lotus" /></a>
|
||||
<a href=""><img src="https://img.shields.io/badge/golang-%3E%3D1.14.7-blue.svg" /></a>
|
||||
<br>
|
||||
</p>
|
||||
|
||||
Lotus is an implementation of the Filecoin Distributed Storage Network. For more details about Filecoin, check out the [Filecoin Spec](https://spec.filecoin.io).
|
||||
|
||||
## Building & Documentation
|
||||
|
||||
For instructions on how to build lotus from source, please visit [https://docs.lotu.sh](https://docs.lotu.sh) or read the source [here](https://github.com/filecoin-project/lotus/tree/master/documentation).
|
||||
For instructions on how to build lotus from source, please visit [https://lotu.sh](https://lotu.sh) or read the source [here](https://github.com/filecoin-project/lotus/tree/master/documentation).
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
@@ -14,13 +26,23 @@ Please send an email to security@filecoin.org. See our [security policy](SECURIT
|
||||
|
||||
## Development
|
||||
|
||||
All work is tracked via issues. An attempt at keeping an up-to-date view on remaining work is in the [lotus testnet github project board](https://github.com/filecoin-project/lotus/projects/1).
|
||||
|
||||
The main branches under development at the moment are:
|
||||
* [`master`](https://github.com/filecoin-project/lotus): current testnet.
|
||||
* [`next`](https://github.com/filecoin-project/lotus/tree/next): working branch with chain-breaking changes.
|
||||
* [`ntwk-calibration`](https://github.com/filecoin-project/lotus/tree/ntwk-calibration): devnet running one of `next` commits.
|
||||
|
||||
### Tracker
|
||||
|
||||
All work is tracked via issues. An attempt at keeping an up-to-date view on remaining work towards Mainnet launch can be seen at the [lotus github project board](https://github.com/orgs/filecoin-project/projects/8). The issues labeled with `incentives` are there to identify the issues needed for Space Race launch.
|
||||
|
||||
### Packages
|
||||
|
||||
The lotus Filecoin implementation unfolds into the following packages:
|
||||
|
||||
- [This repo](https://github.com/filecoin-project/lotus)
|
||||
- [go-fil-markets](https://github.com/filecoin-project/go-fil-markets) which has its own [kanban work tracker available here](https://app.zenhub.com/workspaces/markets-shared-components-5daa144a7046a60001c6e253/board)
|
||||
- [spec-actors](https://github.com/filecoin-project/specs-actors) which has its own [kanban work tracker available here](https://app.zenhub.com/workspaces/actors-5ee6f3aa87591f0016c05685/board)
|
||||
|
||||
## License
|
||||
|
||||
Dual-licensed under [MIT](https://github.com/filecoin-project/lotus/blob/master/LICENSE-MIT) + [Apache 2.0](https://github.com/filecoin-project/lotus/blob/master/LICENSE-APACHE)
|
||||
|
||||
+22
-2
@@ -4,10 +4,11 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/go-jsonrpc/auth"
|
||||
metrics "github.com/libp2p/go-libp2p-core/metrics"
|
||||
"github.com/libp2p/go-libp2p-core/network"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
|
||||
"github.com/filecoin-project/go-jsonrpc/auth"
|
||||
protocol "github.com/libp2p/go-libp2p-core/protocol"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
)
|
||||
@@ -28,6 +29,20 @@ type Common interface {
|
||||
NetDisconnect(context.Context, peer.ID) error
|
||||
NetFindPeer(context.Context, peer.ID) (peer.AddrInfo, error)
|
||||
NetPubsubScores(context.Context) ([]PubsubScore, error)
|
||||
NetAutoNatStatus(context.Context) (NatInfo, error)
|
||||
NetAgentVersion(ctx context.Context, p peer.ID) (string, error)
|
||||
|
||||
// NetBandwidthStats returns statistics about the nodes total bandwidth
|
||||
// usage and current rate across all peers and protocols.
|
||||
NetBandwidthStats(ctx context.Context) (metrics.Stats, error)
|
||||
|
||||
// NetBandwidthStatsByPeer returns statistics about the nodes bandwidth
|
||||
// usage and current rate per peer
|
||||
NetBandwidthStatsByPeer(ctx context.Context) (map[string]metrics.Stats, error)
|
||||
|
||||
// NetBandwidthStatsByProtocol returns statistics about the nodes bandwidth
|
||||
// usage and current rate per protocol
|
||||
NetBandwidthStatsByProtocol(ctx context.Context) (map[protocol.ID]metrics.Stats, error)
|
||||
|
||||
// MethodGroup: Common
|
||||
|
||||
@@ -65,3 +80,8 @@ type Version struct {
|
||||
func (v Version) String() string {
|
||||
return fmt.Sprintf("%s+api%s", v.Version, v.APIVersion.String())
|
||||
}
|
||||
|
||||
type NatInfo struct {
|
||||
Reachability network.Reachability
|
||||
PublicAddr string
|
||||
}
|
||||
|
||||
+277
-60
@@ -2,23 +2,32 @@ package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/dline"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime/proof"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-filestore"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-bitfield"
|
||||
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
||||
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"github.com/filecoin-project/go-multistore"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/market"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
marketevents "github.com/filecoin-project/lotus/markets/loggers"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
)
|
||||
|
||||
@@ -37,8 +46,11 @@ type FullNode interface {
|
||||
// ChainHead returns the current head of the chain.
|
||||
ChainHead(context.Context) (*types.TipSet, error)
|
||||
|
||||
// ChainGetRandomness is used to sample the chain for randomness.
|
||||
ChainGetRandomness(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error)
|
||||
// ChainGetRandomnessFromTickets is used to sample the chain for randomness.
|
||||
ChainGetRandomnessFromTickets(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error)
|
||||
|
||||
// ChainGetRandomnessFromBeacon is used to sample the beacon for randomness.
|
||||
ChainGetRandomnessFromBeacon(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error)
|
||||
|
||||
// ChainGetBlock returns the block specified by the given CID.
|
||||
ChainGetBlock(context.Context, cid.Cid) (*types.BlockHeader, error)
|
||||
@@ -67,7 +79,11 @@ type FullNode interface {
|
||||
|
||||
// ChainHasObj checks if a given CID exists in the chain blockstore.
|
||||
ChainHasObj(context.Context, cid.Cid) (bool, error)
|
||||
ChainStatObj(context.Context, cid.Cid, cid.Cid) (ObjStat, error)
|
||||
|
||||
// ChainStatObj returns statistics about the graph referenced by 'obj'.
|
||||
// If 'base' is also specified, then the returned stat will be a diff
|
||||
// between the two objects.
|
||||
ChainStatObj(ctx context.Context, obj cid.Cid, base cid.Cid) (ObjStat, error)
|
||||
|
||||
// ChainSetHead forcefully sets current chain head. Use with caution.
|
||||
ChainSetHead(context.Context, types.TipSetKey) error
|
||||
@@ -99,7 +115,34 @@ type FullNode interface {
|
||||
ChainGetPath(ctx context.Context, from types.TipSetKey, to types.TipSetKey) ([]*HeadChange, error)
|
||||
|
||||
// ChainExport returns a stream of bytes with CAR dump of chain data.
|
||||
ChainExport(context.Context, types.TipSetKey) (<-chan []byte, error)
|
||||
// The exported chain data includes the header chain from the given tipset
|
||||
// back to genesis, the entire genesis state, and the most recent 'nroots'
|
||||
// state trees.
|
||||
ChainExport(ctx context.Context, nroots abi.ChainEpoch, tsk types.TipSetKey) (<-chan []byte, error)
|
||||
|
||||
// MethodGroup: Beacon
|
||||
// The Beacon method group contains methods for interacting with the random beacon (DRAND)
|
||||
|
||||
// BeaconGetEntry returns the beacon entry for the given filecoin epoch. If
|
||||
// the entry has not yet been produced, the call will block until the entry
|
||||
// becomes available
|
||||
BeaconGetEntry(ctx context.Context, epoch abi.ChainEpoch) (*types.BeaconEntry, error)
|
||||
|
||||
// GasEstimateFeeCap estimates gas fee cap
|
||||
GasEstimateFeeCap(context.Context, *types.Message, int64, types.TipSetKey) (types.BigInt, error)
|
||||
|
||||
// GasEstimateGasLimit estimates gas used by the message and returns it.
|
||||
// It fails if message fails to execute.
|
||||
GasEstimateGasLimit(context.Context, *types.Message, types.TipSetKey) (int64, error)
|
||||
|
||||
// GasEstimateGasPremium estimates what gas price should be used for a
|
||||
// message to have high likelihood of inclusion in `nblocksincl` epochs.
|
||||
|
||||
GasEstimateGasPremium(_ context.Context, nblocksincl uint64,
|
||||
sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error)
|
||||
|
||||
// GasEstimateMessageGas estimates gas values for unset message gas fields
|
||||
GasEstimateMessageGas(context.Context, *types.Message, *MessageSendSpec, types.TipSetKey) (*types.Message, error)
|
||||
|
||||
// MethodGroup: Sync
|
||||
// The Sync method group contains methods for interacting with and
|
||||
@@ -116,10 +159,16 @@ type FullNode interface {
|
||||
// yet synced block headers.
|
||||
SyncIncomingBlocks(ctx context.Context) (<-chan *types.BlockHeader, error)
|
||||
|
||||
// SyncCheckpoint marks a blocks as checkpointed, meaning that it won't ever fork away from it.
|
||||
SyncCheckpoint(ctx context.Context, tsk types.TipSetKey) error
|
||||
|
||||
// SyncMarkBad marks a blocks as bad, meaning that it won't ever by synced.
|
||||
// Use with extreme caution.
|
||||
SyncMarkBad(ctx context.Context, bcid cid.Cid) error
|
||||
|
||||
// SyncUnmarkBad unmarks a blocks as bad, making it possible to be validated and synced again.
|
||||
SyncUnmarkBad(ctx context.Context, bcid cid.Cid) 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)
|
||||
@@ -131,21 +180,32 @@ type FullNode interface {
|
||||
// MpoolPending returns pending mempool messages.
|
||||
MpoolPending(context.Context, types.TipSetKey) ([]*types.SignedMessage, error)
|
||||
|
||||
// MpoolSelect returns a list of pending messages for inclusion in the next block
|
||||
MpoolSelect(context.Context, types.TipSetKey, float64) ([]*types.SignedMessage, error)
|
||||
|
||||
// MpoolPush pushes a signed message to mempool.
|
||||
MpoolPush(context.Context, *types.SignedMessage) (cid.Cid, error)
|
||||
|
||||
// MpoolPushMessage atomically assigns a nonce, signs, and pushes a message
|
||||
// to mempool.
|
||||
MpoolPushMessage(context.Context, *types.Message) (*types.SignedMessage, error)
|
||||
// maxFee is only used when GasFeeCap/GasPremium fields aren't specified
|
||||
//
|
||||
// When maxFee is set to 0, MpoolPushMessage will guess appropriate fee
|
||||
// based on current chain conditions
|
||||
MpoolPushMessage(ctx context.Context, msg *types.Message, spec *MessageSendSpec) (*types.SignedMessage, error)
|
||||
|
||||
// MpoolGetNonce gets next nonce for the specified sender.
|
||||
// Note that this method may not be atomic. Use MpoolPushMessage instead.
|
||||
MpoolGetNonce(context.Context, address.Address) (uint64, error)
|
||||
MpoolSub(context.Context) (<-chan MpoolUpdate, error)
|
||||
|
||||
// MpoolEstimateGasPrice estimates what gas price should be used for a
|
||||
// message to have high likelihood of inclusion in `nblocksincl` epochs.
|
||||
MpoolEstimateGasPrice(ctx context.Context, nblocksincl uint64, sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error)
|
||||
// MpoolClear clears pending messages from the mpool
|
||||
MpoolClear(context.Context, bool) error
|
||||
|
||||
// MpoolGetConfig returns (a copy of) the current mpool config
|
||||
MpoolGetConfig(context.Context) (*types.MpoolConfig, error)
|
||||
// MpoolSetConfig sets the mpool config to (a copy of) the supplied config
|
||||
MpoolSetConfig(context.Context, *types.MpoolConfig) error
|
||||
|
||||
// MethodGroup: Miner
|
||||
|
||||
@@ -189,27 +249,42 @@ type FullNode interface {
|
||||
// retrieval markets as a client
|
||||
|
||||
// ClientImport imports file under the specified path into filestore.
|
||||
ClientImport(ctx context.Context, ref FileRef) (cid.Cid, error)
|
||||
ClientImport(ctx context.Context, ref FileRef) (*ImportRes, error)
|
||||
// ClientRemoveImport removes file import
|
||||
ClientRemoveImport(ctx context.Context, importID multistore.StoreID) error
|
||||
// ClientStartDeal proposes a deal with a miner.
|
||||
ClientStartDeal(ctx context.Context, params *StartDealParams) (*cid.Cid, error)
|
||||
// ClientGetDealInfo returns the latest information about a given deal.
|
||||
ClientGetDealInfo(context.Context, cid.Cid) (*DealInfo, error)
|
||||
// ClientListDeals returns information about the deals made by the local client.
|
||||
ClientListDeals(ctx context.Context) ([]DealInfo, error)
|
||||
// ClientGetDealUpdates returns the status of updated deals
|
||||
ClientGetDealUpdates(ctx context.Context) (<-chan DealInfo, error)
|
||||
// ClientHasLocal indicates whether a certain CID is locally stored.
|
||||
ClientHasLocal(ctx context.Context, root cid.Cid) (bool, error)
|
||||
// ClientFindData identifies peers that have a certain file, and returns QueryOffers (one per peer).
|
||||
ClientFindData(ctx context.Context, root cid.Cid) ([]QueryOffer, error)
|
||||
ClientFindData(ctx context.Context, root cid.Cid, piece *cid.Cid) ([]QueryOffer, error)
|
||||
// ClientMinerQueryOffer returns a QueryOffer for the specific miner and file.
|
||||
ClientMinerQueryOffer(ctx context.Context, root cid.Cid, miner address.Address) (QueryOffer, error)
|
||||
ClientMinerQueryOffer(ctx context.Context, miner address.Address, root cid.Cid, piece *cid.Cid) (QueryOffer, error)
|
||||
// ClientRetrieve initiates the retrieval of a file, as specified in the order.
|
||||
ClientRetrieve(ctx context.Context, order RetrievalOrder, ref *FileRef) error
|
||||
// ClientRetrieveWithEvents initiates the retrieval of a file, as specified in the order, and provides a channel
|
||||
// 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)
|
||||
// ClientCalcCommP calculates the CommP for a specified file, based on the sector size of the provided miner.
|
||||
ClientCalcCommP(ctx context.Context, inpath string, miner address.Address) (*CommPRet, 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.
|
||||
ClientGenCar(ctx context.Context, ref FileRef, outpath string) error
|
||||
// ClientDealSize calculates real deal data size
|
||||
ClientDealSize(ctx context.Context, root cid.Cid) (DataSize, error)
|
||||
// ClientListTransfers returns the status of all ongoing transfers of data
|
||||
ClientListDataTransfers(ctx context.Context) ([]DataTransferChannel, error)
|
||||
ClientDataTransferUpdates(ctx context.Context) (<-chan DataTransferChannel, 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
|
||||
|
||||
// ClientUnimport removes references to the specified file from filestore
|
||||
//ClientUnimport(path string)
|
||||
@@ -240,33 +315,42 @@ type FullNode interface {
|
||||
// StateMinerSectors returns info about the given miner's sectors. If the filter bitfield is nil, all sectors are included.
|
||||
// If the filterOut boolean is set to true, any sectors in the filter are excluded.
|
||||
// If false, only those sectors in the filter are included.
|
||||
StateMinerSectors(context.Context, address.Address, *abi.BitField, bool, types.TipSetKey) ([]*ChainSectorInfo, error)
|
||||
// StateMinerProvingSet returns info about those sectors that a given miner is actively proving.
|
||||
StateMinerProvingSet(context.Context, address.Address, types.TipSetKey) ([]*ChainSectorInfo, error)
|
||||
StateMinerSectors(context.Context, address.Address, *bitfield.BitField, bool, types.TipSetKey) ([]*ChainSectorInfo, error)
|
||||
// StateMinerActiveSectors returns info about sectors that a given miner is actively proving.
|
||||
StateMinerActiveSectors(context.Context, address.Address, types.TipSetKey) ([]*ChainSectorInfo, error)
|
||||
// StateMinerProvingDeadline calculates the deadline at some epoch for a proving period
|
||||
// and returns the deadline-related calculations.
|
||||
StateMinerProvingDeadline(context.Context, address.Address, types.TipSetKey) (*miner.DeadlineInfo, error)
|
||||
StateMinerProvingDeadline(context.Context, address.Address, types.TipSetKey) (*dline.Info, error)
|
||||
// StateMinerPower returns the power of the indicated miner
|
||||
StateMinerPower(context.Context, address.Address, types.TipSetKey) (*MinerPower, error)
|
||||
// StateMinerInfo returns info about the indicated miner
|
||||
StateMinerInfo(context.Context, address.Address, types.TipSetKey) (MinerInfo, error)
|
||||
// StateMinerDeadlines returns all the proving deadlines for the given miner
|
||||
StateMinerDeadlines(context.Context, address.Address, types.TipSetKey) (*miner.Deadlines, error)
|
||||
StateMinerDeadlines(context.Context, address.Address, types.TipSetKey) ([]*miner.Deadline, error)
|
||||
// StateMinerPartitions loads miner partitions for the specified miner/deadline
|
||||
StateMinerPartitions(context.Context, address.Address, uint64, types.TipSetKey) ([]*miner.Partition, error)
|
||||
// StateMinerFaults returns a bitfield indicating the faulty sectors of the given miner
|
||||
StateMinerFaults(context.Context, address.Address, types.TipSetKey) (*abi.BitField, error)
|
||||
StateMinerFaults(context.Context, address.Address, types.TipSetKey) (bitfield.BitField, error)
|
||||
// StateAllMinerFaults returns all non-expired Faults that occur within lookback epochs of the given tipset
|
||||
StateAllMinerFaults(ctx context.Context, lookback abi.ChainEpoch, ts types.TipSetKey) ([]*Fault, error)
|
||||
// StateMinerRecoveries returns a bitfield indicating the recovering sectors of the given miner
|
||||
StateMinerRecoveries(context.Context, address.Address, types.TipSetKey) (*abi.BitField, error)
|
||||
StateMinerRecoveries(context.Context, address.Address, types.TipSetKey) (bitfield.BitField, error)
|
||||
// StateMinerInitialPledgeCollateral returns the precommit deposit for the specified miner's sector
|
||||
StateMinerPreCommitDepositForPower(context.Context, address.Address, miner.SectorPreCommitInfo, types.TipSetKey) (types.BigInt, error)
|
||||
// StateMinerInitialPledgeCollateral returns the initial pledge collateral for the specified miner's sector
|
||||
StateMinerInitialPledgeCollateral(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (types.BigInt, error)
|
||||
StateMinerInitialPledgeCollateral(context.Context, address.Address, miner.SectorPreCommitInfo, types.TipSetKey) (types.BigInt, error)
|
||||
// StateMinerAvailableBalance returns the portion of a miner's balance that can be withdrawn or spent
|
||||
StateMinerAvailableBalance(context.Context, address.Address, types.TipSetKey) (types.BigInt, error)
|
||||
// StateSectorPreCommitInfo returns the PreCommit info for the specified miner's sector
|
||||
StateSectorPreCommitInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error)
|
||||
// StateSectorGetInfo returns the on-chain info for the specified miner's sector
|
||||
// StateSectorGetInfo returns the on-chain info for the specified miner's sector. Returns null in case the sector info isn't found
|
||||
// NOTE: returned info.Expiration may not be accurate in some cases, use StateSectorExpiration to get accurate
|
||||
// expiration epoch
|
||||
StateSectorGetInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorOnChainInfo, error)
|
||||
StatePledgeCollateral(context.Context, types.TipSetKey) (types.BigInt, error)
|
||||
// StateSectorExpiration returns epoch at which given sector will expire
|
||||
StateSectorExpiration(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*SectorExpiration, error)
|
||||
// StateSectorPartition finds deadline/partition with the specified sector
|
||||
StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok types.TipSetKey) (*SectorLocation, error)
|
||||
// StateSearchMsg searches for a message in the chain, and returns its receipt and the tipset where it was executed
|
||||
StateSearchMsg(context.Context, cid.Cid) (*MsgLookup, error)
|
||||
// StateWaitMsg looks back in the chain for a message. If not found, it blocks until the
|
||||
@@ -298,6 +382,16 @@ type FullNode interface {
|
||||
// StateCompute is a flexible command that applies the given messages on the given tipset.
|
||||
// The messages are run as though the VM were at the provided height.
|
||||
StateCompute(context.Context, abi.ChainEpoch, []*types.Message, types.TipSetKey) (*ComputeStateOutput, error)
|
||||
// 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) (*verifreg.DataCap, 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)
|
||||
|
||||
// MethodGroup: Msig
|
||||
// The Msig methods are used to interact with multisig wallets on the
|
||||
@@ -305,10 +399,13 @@ 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)
|
||||
// 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)
|
||||
// MsigCreate creates a multisig wallet
|
||||
// It takes the following params: <required number of senders>, <approving addresses>, <unlock duration>
|
||||
//<initial balance>, <sender address of the create msg>, <gas price>
|
||||
MsigCreate(context.Context, int64, []address.Address, abi.ChainEpoch, types.BigInt, address.Address, types.BigInt) (cid.Cid, error)
|
||||
MsigCreate(context.Context, uint64, []address.Address, abi.ChainEpoch, types.BigInt, address.Address, types.BigInt) (cid.Cid, error)
|
||||
// MsigPropose proposes a multisig message
|
||||
// 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>
|
||||
@@ -321,17 +418,29 @@ type FullNode interface {
|
||||
// It takes the following params: <multisig address>, <proposed message 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
|
||||
// It takes the following params: <multisig address>, <sender address of the propose msg>,
|
||||
// <new signer>, <whether the number of required signers should be increased>
|
||||
MsigAddPropose(context.Context, address.Address, address.Address, address.Address, bool) (cid.Cid, error)
|
||||
// MsigAddApprove approves a previously proposed AddSigner message
|
||||
// It takes the following params: <multisig address>, <sender address of the approve msg>, <proposed message ID>,
|
||||
// <proposer address>, <new signer>, <whether the number of required signers should be increased>
|
||||
MsigAddApprove(context.Context, address.Address, address.Address, uint64, address.Address, address.Address, bool) (cid.Cid, error)
|
||||
// MsigAddCancel cancels a previously proposed AddSigner message
|
||||
// It takes the following params: <multisig address>, <sender address of the cancel msg>, <proposed message ID>,
|
||||
// <new signer>, <whether the number of required signers should be increased>
|
||||
MsigAddCancel(context.Context, address.Address, address.Address, uint64, address.Address, bool) (cid.Cid, error)
|
||||
// MsigSwapPropose proposes swapping 2 signers in the multisig
|
||||
// It takes the following params: <multisig address>, <sender address of the propose msg>,
|
||||
// <old signer> <new signer>
|
||||
// <old signer>, <new signer>
|
||||
MsigSwapPropose(context.Context, address.Address, address.Address, address.Address, address.Address) (cid.Cid, error)
|
||||
// MsigSwapApprove approves a previously proposed SwapSigner
|
||||
// It takes the following params: <multisig address>, <sender address of the approve msg>, <proposed message ID>,
|
||||
// <proposer address>, <old signer> <new signer>
|
||||
// <proposer address>, <old signer>, <new signer>
|
||||
MsigSwapApprove(context.Context, address.Address, address.Address, uint64, address.Address, address.Address, address.Address) (cid.Cid, error)
|
||||
// MsigSwapCancel cancels a previously proposed SwapSigner message
|
||||
// It takes the following params: <multisig address>, <sender address of the cancel msg>, <proposed message ID>,
|
||||
// <old signer> <new signer>
|
||||
// <old signer>, <new signer>
|
||||
MsigSwapCancel(context.Context, address.Address, address.Address, uint64, address.Address, address.Address) (cid.Cid, error)
|
||||
|
||||
MarketEnsureAvailable(context.Context, address.Address, address.Address, types.BigInt) (cid.Cid, error)
|
||||
@@ -340,18 +449,22 @@ type FullNode interface {
|
||||
// MethodGroup: Paych
|
||||
// The Paych methods are for interacting with and managing payment channels
|
||||
|
||||
PaychGet(ctx context.Context, from, to address.Address, ensureFunds types.BigInt) (*ChannelInfo, error)
|
||||
PaychGet(ctx context.Context, from, to address.Address, amt types.BigInt) (*ChannelInfo, error)
|
||||
PaychGetWaitReady(context.Context, cid.Cid) (address.Address, error)
|
||||
PaychAvailableFunds(ch address.Address) (*ChannelAvailableFunds, error)
|
||||
PaychAvailableFundsByFromTo(from, to address.Address) (*ChannelAvailableFunds, error)
|
||||
PaychList(context.Context) ([]address.Address, error)
|
||||
PaychStatus(context.Context, address.Address) (*PaychStatus, error)
|
||||
PaychClose(context.Context, address.Address) (cid.Cid, error)
|
||||
PaychSettle(context.Context, address.Address) (cid.Cid, error)
|
||||
PaychCollect(context.Context, address.Address) (cid.Cid, error)
|
||||
PaychAllocateLane(ctx context.Context, ch address.Address) (uint64, error)
|
||||
PaychNewPayment(ctx context.Context, from, to address.Address, vouchers []VoucherSpec) (*PaymentInfo, error)
|
||||
PaychVoucherCheckValid(context.Context, address.Address, *paych.SignedVoucher) error
|
||||
PaychVoucherCheckSpendable(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (bool, error)
|
||||
PaychVoucherCreate(context.Context, address.Address, types.BigInt, uint64) (*paych.SignedVoucher, error)
|
||||
PaychVoucherCreate(context.Context, address.Address, types.BigInt, uint64) (*VoucherCreateResult, error)
|
||||
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) (cid.Cid, error)
|
||||
PaychVoucherSubmit(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (cid.Cid, error)
|
||||
}
|
||||
|
||||
type FileRef struct {
|
||||
@@ -360,15 +473,35 @@ type FileRef struct {
|
||||
}
|
||||
|
||||
type MinerSectors struct {
|
||||
Sset uint64
|
||||
Pset uint64
|
||||
Sectors uint64
|
||||
Active uint64
|
||||
}
|
||||
|
||||
type SectorExpiration struct {
|
||||
OnTime abi.ChainEpoch
|
||||
|
||||
// non-zero if sector is faulty, epoch at which it will be permanently
|
||||
// removed if it doesn't recover
|
||||
Early abi.ChainEpoch
|
||||
}
|
||||
|
||||
type SectorLocation struct {
|
||||
Deadline uint64
|
||||
Partition uint64
|
||||
}
|
||||
|
||||
type ImportRes struct {
|
||||
Root cid.Cid
|
||||
ImportID multistore.StoreID
|
||||
}
|
||||
|
||||
type Import struct {
|
||||
Status filestore.Status
|
||||
Key cid.Cid
|
||||
Key multistore.StoreID
|
||||
Err string
|
||||
|
||||
Root *cid.Cid
|
||||
Source string
|
||||
FilePath string
|
||||
Size uint64
|
||||
}
|
||||
|
||||
type DealInfo struct {
|
||||
@@ -377,6 +510,7 @@ type DealInfo struct {
|
||||
Message string // more information about deal state, particularly errors
|
||||
Provider address.Address
|
||||
|
||||
DataRef *storagemarket.DataRef
|
||||
PieceCID cid.Cid
|
||||
Size uint64
|
||||
|
||||
@@ -384,9 +518,12 @@ type DealInfo struct {
|
||||
Duration uint64
|
||||
|
||||
DealID abi.DealID
|
||||
|
||||
CreationTime time.Time
|
||||
}
|
||||
|
||||
type MsgLookup struct {
|
||||
Message cid.Cid // Can be different than requested, in case it was replaced, but only gas values changed
|
||||
Receipt types.MessageReceipt
|
||||
ReturnDec interface{}
|
||||
TipSet types.TipSetKey
|
||||
@@ -429,14 +566,36 @@ type PaychStatus struct {
|
||||
}
|
||||
|
||||
type ChannelInfo struct {
|
||||
Channel address.Address
|
||||
ChannelMessage cid.Cid
|
||||
Channel address.Address
|
||||
WaitSentinel cid.Cid
|
||||
}
|
||||
|
||||
type ChannelAvailableFunds struct {
|
||||
// Channel is the address of the channel
|
||||
Channel *address.Address
|
||||
// From is the from address of the channel (channel creator)
|
||||
From address.Address
|
||||
// To is the to address of the channel
|
||||
To address.Address
|
||||
// ConfirmedAmt is the amount of funds that have been confirmed on-chain
|
||||
// for the channel
|
||||
ConfirmedAmt types.BigInt
|
||||
// PendingAmt is the amount of funds that are pending confirmation on-chain
|
||||
PendingAmt types.BigInt
|
||||
// PendingWaitSentinel can be used with PaychGetWaitReady to wait for
|
||||
// confirmation of pending funds
|
||||
PendingWaitSentinel *cid.Cid
|
||||
// QueuedAmt is the amount that is queued up behind a pending request
|
||||
QueuedAmt types.BigInt
|
||||
// VoucherRedeemedAmt is the amount that is redeemed by vouchers on-chain
|
||||
// and in the local datastore
|
||||
VoucherReedeemedAmt types.BigInt
|
||||
}
|
||||
|
||||
type PaymentInfo struct {
|
||||
Channel address.Address
|
||||
ChannelMessage *cid.Cid
|
||||
Vouchers []*paych.SignedVoucher
|
||||
Channel address.Address
|
||||
WaitSentinel cid.Cid
|
||||
Vouchers []*paych.SignedVoucher
|
||||
}
|
||||
|
||||
type VoucherSpec struct {
|
||||
@@ -448,6 +607,16 @@ type VoucherSpec struct {
|
||||
Extra *paych.ModVerifyParams
|
||||
}
|
||||
|
||||
// VoucherCreateResult is the response to calling PaychVoucherCreate
|
||||
type VoucherCreateResult struct {
|
||||
// Voucher that was created, or nil if there was an error or if there
|
||||
// were insufficient funds in the channel
|
||||
Voucher *paych.SignedVoucher
|
||||
// Shortfall is the additional amount that would be needed in the channel
|
||||
// in order to be able to create the voucher
|
||||
Shortfall types.BigInt
|
||||
}
|
||||
|
||||
type MinerPower struct {
|
||||
MinerPower power.Claim
|
||||
TotalPower power.Claim
|
||||
@@ -456,27 +625,31 @@ type MinerPower struct {
|
||||
type QueryOffer struct {
|
||||
Err string
|
||||
|
||||
Root cid.Cid
|
||||
Root cid.Cid
|
||||
Piece *cid.Cid
|
||||
|
||||
Size uint64
|
||||
MinPrice types.BigInt
|
||||
UnsealPrice types.BigInt
|
||||
PaymentInterval uint64
|
||||
PaymentIntervalIncrease uint64
|
||||
Miner address.Address
|
||||
MinerPeerID peer.ID
|
||||
MinerPeer retrievalmarket.RetrievalPeer
|
||||
}
|
||||
|
||||
func (o *QueryOffer) Order(client address.Address) RetrievalOrder {
|
||||
return RetrievalOrder{
|
||||
Root: o.Root,
|
||||
Piece: o.Piece,
|
||||
Size: o.Size,
|
||||
Total: o.MinPrice,
|
||||
UnsealPrice: o.UnsealPrice,
|
||||
PaymentInterval: o.PaymentInterval,
|
||||
PaymentIntervalIncrease: o.PaymentIntervalIncrease,
|
||||
Client: client,
|
||||
|
||||
Miner: o.Miner,
|
||||
MinerPeerID: o.MinerPeerID,
|
||||
Miner: o.Miner,
|
||||
MinerPeer: o.MinerPeer,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,15 +665,17 @@ type MarketDeal struct {
|
||||
|
||||
type RetrievalOrder struct {
|
||||
// TODO: make this less unixfs specific
|
||||
Root cid.Cid
|
||||
Size uint64
|
||||
Root cid.Cid
|
||||
Piece *cid.Cid
|
||||
Size uint64
|
||||
// TODO: support offset
|
||||
Total types.BigInt
|
||||
UnsealPrice types.BigInt
|
||||
PaymentInterval uint64
|
||||
PaymentIntervalIncrease uint64
|
||||
Client address.Address
|
||||
Miner address.Address
|
||||
MinerPeerID peer.ID
|
||||
MinerPeer retrievalmarket.RetrievalPeer
|
||||
}
|
||||
|
||||
type InvocResult struct {
|
||||
@@ -517,12 +692,15 @@ type MethodCall struct {
|
||||
}
|
||||
|
||||
type StartDealParams struct {
|
||||
Data *storagemarket.DataRef
|
||||
Wallet address.Address
|
||||
Miner address.Address
|
||||
EpochPrice types.BigInt
|
||||
MinBlocksDuration uint64
|
||||
DealStartEpoch abi.ChainEpoch
|
||||
Data *storagemarket.DataRef
|
||||
Wallet address.Address
|
||||
Miner address.Address
|
||||
EpochPrice types.BigInt
|
||||
MinBlocksDuration uint64
|
||||
ProviderCollateral big.Int
|
||||
DealStartEpoch abi.ChainEpoch
|
||||
FastRetrieval bool
|
||||
VerifiedDeal bool
|
||||
}
|
||||
|
||||
type IpldObject struct {
|
||||
@@ -555,8 +733,28 @@ const (
|
||||
StageMessages
|
||||
StageSyncComplete
|
||||
StageSyncErrored
|
||||
StageFetchingMessages
|
||||
)
|
||||
|
||||
func (v SyncStateStage) String() string {
|
||||
switch v {
|
||||
case StageHeaders:
|
||||
return "header sync"
|
||||
case StagePersistHeaders:
|
||||
return "persisting headers"
|
||||
case StageMessages:
|
||||
return "message sync"
|
||||
case StageSyncComplete:
|
||||
return "complete"
|
||||
case StageSyncErrored:
|
||||
return "error"
|
||||
case StageFetchingMessages:
|
||||
return "fetching messages"
|
||||
default:
|
||||
return fmt.Sprintf("<unknown: %d>", v)
|
||||
}
|
||||
}
|
||||
|
||||
type MpoolChange int
|
||||
|
||||
const (
|
||||
@@ -574,14 +772,28 @@ type ComputeStateOutput struct {
|
||||
Trace []*InvocResult
|
||||
}
|
||||
|
||||
type DealCollateralBounds struct {
|
||||
Min abi.TokenAmount
|
||||
Max abi.TokenAmount
|
||||
}
|
||||
|
||||
type CirculatingSupply struct {
|
||||
FilVested abi.TokenAmount
|
||||
FilMined abi.TokenAmount
|
||||
FilBurnt abi.TokenAmount
|
||||
FilLocked abi.TokenAmount
|
||||
FilCirculating abi.TokenAmount
|
||||
}
|
||||
|
||||
type MiningBaseInfo struct {
|
||||
MinerPower types.BigInt
|
||||
NetworkPower types.BigInt
|
||||
Sectors []abi.SectorInfo
|
||||
Sectors []proof.SectorInfo
|
||||
WorkerKey address.Address
|
||||
SectorSize abi.SectorSize
|
||||
PrevBeaconEntry types.BeaconEntry
|
||||
BeaconEntries []types.BeaconEntry
|
||||
HasMinPower bool
|
||||
}
|
||||
|
||||
type BlockTemplate struct {
|
||||
@@ -593,7 +805,12 @@ type BlockTemplate struct {
|
||||
Messages []*types.SignedMessage
|
||||
Epoch abi.ChainEpoch
|
||||
Timestamp uint64
|
||||
WinningPoStProof []abi.PoStProof
|
||||
WinningPoStProof []proof.PoStProof
|
||||
}
|
||||
|
||||
type DataSize struct {
|
||||
PayloadSize int64
|
||||
PieceSize abi.PaddedPieceSize
|
||||
}
|
||||
|
||||
type CommPRet struct {
|
||||
|
||||
+65
-16
@@ -3,15 +3,19 @@ package api
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-fil-markets/piecestore"
|
||||
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
||||
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/sector-storage/stores"
|
||||
"github.com/filecoin-project/sector-storage/storiface"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/fsutil"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/stores"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/storiface"
|
||||
)
|
||||
|
||||
// StorageMiner is a low-level interface to the Filecoin network storage miner node
|
||||
@@ -28,31 +32,55 @@ type StorageMiner interface {
|
||||
PledgeSector(context.Context) error
|
||||
|
||||
// Get the status of a given sector by ID
|
||||
SectorsStatus(context.Context, abi.SectorNumber) (SectorInfo, error)
|
||||
SectorsStatus(ctx context.Context, sid abi.SectorNumber, showOnChainInfo bool) (SectorInfo, error)
|
||||
|
||||
// List all staged sectors
|
||||
SectorsList(context.Context) ([]abi.SectorNumber, error)
|
||||
|
||||
SectorsRefs(context.Context) (map[string][]SealedRef, error)
|
||||
|
||||
// SectorStartSealing can be called on sectors in Empty or WaitDeals states
|
||||
// to trigger sealing early
|
||||
SectorStartSealing(context.Context, abi.SectorNumber) error
|
||||
// SectorSetSealDelay sets the time that a newly-created sector
|
||||
// waits for more deals before it starts sealing
|
||||
SectorSetSealDelay(context.Context, time.Duration) error
|
||||
// SectorGetSealDelay gets the time that a newly-created sector
|
||||
// waits for more deals before it starts sealing
|
||||
SectorGetSealDelay(context.Context) (time.Duration, error)
|
||||
// SectorSetExpectedSealDuration sets the expected time for a sector to seal
|
||||
SectorSetExpectedSealDuration(context.Context, time.Duration) error
|
||||
// SectorGetExpectedSealDuration gets the expected time for a sector to seal
|
||||
SectorGetExpectedSealDuration(context.Context) (time.Duration, error)
|
||||
SectorsUpdate(context.Context, abi.SectorNumber, SectorState) error
|
||||
SectorRemove(context.Context, abi.SectorNumber) error
|
||||
SectorMarkForUpgrade(ctx context.Context, id abi.SectorNumber) error
|
||||
|
||||
StorageList(ctx context.Context) (map[stores.ID][]stores.Decl, error)
|
||||
StorageLocal(ctx context.Context) (map[stores.ID]string, error)
|
||||
StorageStat(ctx context.Context, id stores.ID) (stores.FsStat, error)
|
||||
StorageStat(ctx context.Context, id stores.ID) (fsutil.FsStat, error)
|
||||
|
||||
// WorkerConnect tells the node to connect to workers RPC
|
||||
WorkerConnect(context.Context, string) error
|
||||
WorkerStats(context.Context) (map[uint64]storiface.WorkerStats, error)
|
||||
WorkerJobs(context.Context) (map[uint64][]storiface.WorkerJob, error)
|
||||
|
||||
// SealingSchedDiag dumps internal sealing scheduler state
|
||||
SealingSchedDiag(context.Context) (interface{}, error)
|
||||
|
||||
stores.SectorIndex
|
||||
|
||||
MarketImportDealData(ctx context.Context, propcid cid.Cid, path string) error
|
||||
MarketListDeals(ctx context.Context) ([]storagemarket.StorageDeal, error)
|
||||
MarketListRetrievalDeals(ctx context.Context) ([]retrievalmarket.ProviderDealState, error)
|
||||
MarketGetDealUpdates(ctx context.Context) (<-chan storagemarket.MinerDeal, error)
|
||||
MarketListIncompleteDeals(ctx context.Context) ([]storagemarket.MinerDeal, error)
|
||||
MarketSetAsk(ctx context.Context, price types.BigInt, duration abi.ChainEpoch, minPieceSize abi.PaddedPieceSize, maxPieceSize abi.PaddedPieceSize) error
|
||||
MarketSetAsk(ctx context.Context, price types.BigInt, verifiedPrice types.BigInt, duration abi.ChainEpoch, minPieceSize abi.PaddedPieceSize, maxPieceSize abi.PaddedPieceSize) error
|
||||
MarketGetAsk(ctx context.Context) (*storagemarket.SignedStorageAsk, error)
|
||||
MarketSetRetrievalAsk(ctx context.Context, rask *retrievalmarket.Ask) error
|
||||
MarketGetRetrievalAsk(ctx context.Context) (*retrievalmarket.Ask, error)
|
||||
MarketListDataTransfers(ctx context.Context) ([]DataTransferChannel, error)
|
||||
MarketDataTransferUpdates(ctx context.Context) (<-chan DataTransferChannel, error)
|
||||
|
||||
DealsImportData(ctx context.Context, dealPropCid cid.Cid, file string) error
|
||||
DealsList(ctx context.Context) ([]storagemarket.StorageDeal, error)
|
||||
@@ -68,6 +96,11 @@ type StorageMiner interface {
|
||||
DealsSetConsiderOfflineRetrievalDeals(context.Context, bool) error
|
||||
|
||||
StorageAddLocal(ctx context.Context, path string) error
|
||||
|
||||
PiecesListPieces(ctx context.Context) ([]cid.Cid, error)
|
||||
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)
|
||||
}
|
||||
|
||||
type SealRes struct {
|
||||
@@ -87,24 +120,40 @@ type SectorLog struct {
|
||||
}
|
||||
|
||||
type SectorInfo struct {
|
||||
SectorID abi.SectorNumber
|
||||
State SectorState
|
||||
CommD *cid.Cid
|
||||
CommR *cid.Cid
|
||||
Proof []byte
|
||||
Deals []abi.DealID
|
||||
Ticket SealTicket
|
||||
Seed SealSeed
|
||||
Retries uint64
|
||||
SectorID abi.SectorNumber
|
||||
State SectorState
|
||||
CommD *cid.Cid
|
||||
CommR *cid.Cid
|
||||
Proof []byte
|
||||
Deals []abi.DealID
|
||||
Ticket SealTicket
|
||||
Seed SealSeed
|
||||
PreCommitMsg *cid.Cid
|
||||
CommitMsg *cid.Cid
|
||||
Retries uint64
|
||||
ToUpgrade bool
|
||||
|
||||
LastErr string
|
||||
|
||||
Log []SectorLog
|
||||
|
||||
// On Chain Info
|
||||
SealProof abi.RegisteredSealProof // The seal proof type implies the PoSt proof/s
|
||||
Activation abi.ChainEpoch // Epoch during which the sector proof was accepted
|
||||
Expiration abi.ChainEpoch // Epoch during which the sector expires
|
||||
DealWeight abi.DealWeight // Integral of active deals over sector lifetime
|
||||
VerifiedDealWeight abi.DealWeight // Integral of active verified deals over sector lifetime
|
||||
InitialPledge abi.TokenAmount // Pledge collected to commit this sector
|
||||
// Expiration Info
|
||||
OnTime abi.ChainEpoch
|
||||
// non-zero if sector is faulty, epoch at which it will be permanently
|
||||
// removed if it doesn't recover
|
||||
Early abi.ChainEpoch
|
||||
}
|
||||
|
||||
type SealedRef struct {
|
||||
SectorID abi.SectorNumber
|
||||
Offset uint64
|
||||
Offset abi.PaddedPieceSize
|
||||
Size abi.UnpaddedPieceSize
|
||||
}
|
||||
|
||||
|
||||
+10
-6
@@ -6,10 +6,10 @@ import (
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/filecoin-project/sector-storage/sealtasks"
|
||||
"github.com/filecoin-project/sector-storage/stores"
|
||||
"github.com/filecoin-project/sector-storage/storiface"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/sealtasks"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/stores"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/storiface"
|
||||
"github.com/filecoin-project/specs-storage/storage"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
@@ -23,12 +23,16 @@ type WorkerAPI interface {
|
||||
Paths(context.Context) ([]stores.StoragePath, error)
|
||||
Info(context.Context) (storiface.WorkerInfo, error)
|
||||
|
||||
AddPiece(ctx context.Context, sector abi.SectorID, pieceSizes []abi.UnpaddedPieceSize, newPieceSize abi.UnpaddedPieceSize, pieceData storage.Data) (abi.PieceInfo, error)
|
||||
|
||||
storage.Sealer
|
||||
|
||||
MoveStorage(ctx context.Context, sector abi.SectorID) error
|
||||
MoveStorage(ctx context.Context, sector abi.SectorID, types stores.SectorFileType) error
|
||||
|
||||
UnsealPiece(context.Context, abi.SectorID, storiface.UnpaddedByteIndex, abi.UnpaddedPieceSize, abi.SealRandomness, cid.Cid) error
|
||||
ReadPiece(context.Context, io.Writer, abi.SectorID, storiface.UnpaddedByteIndex, abi.UnpaddedPieceSize) error
|
||||
ReadPiece(context.Context, io.Writer, abi.SectorID, storiface.UnpaddedByteIndex, abi.UnpaddedPieceSize) (bool, error)
|
||||
|
||||
StorageAddLocal(ctx context.Context, path string) error
|
||||
|
||||
Fetch(context.Context, abi.SectorID, stores.SectorFileType, stores.PathType, stores.AcquireMode) error
|
||||
|
||||
|
||||
@@ -5,8 +5,9 @@ import (
|
||||
|
||||
blocks "github.com/ipfs/go-block-format"
|
||||
"github.com/ipfs/go-cid"
|
||||
blockstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/lib/blockstore"
|
||||
)
|
||||
|
||||
type ChainIO interface {
|
||||
|
||||
+468
-163
@@ -3,23 +3,34 @@ package apistruct
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/dline"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
metrics "github.com/libp2p/go-libp2p-core/metrics"
|
||||
"github.com/libp2p/go-libp2p-core/network"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
protocol "github.com/libp2p/go-libp2p-core/protocol"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-bitfield"
|
||||
"github.com/filecoin-project/go-fil-markets/piecestore"
|
||||
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
||||
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||
"github.com/filecoin-project/go-jsonrpc/auth"
|
||||
|
||||
"github.com/filecoin-project/sector-storage/sealtasks"
|
||||
"github.com/filecoin-project/sector-storage/stores"
|
||||
"github.com/filecoin-project/sector-storage/storiface"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"github.com/filecoin-project/go-multistore"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/fsutil"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/sealtasks"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/stores"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/storiface"
|
||||
marketevents "github.com/filecoin-project/lotus/markets/loggers"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
"github.com/filecoin-project/specs-storage/storage"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
@@ -36,13 +47,18 @@ type CommonStruct struct {
|
||||
AuthVerify func(ctx context.Context, token string) ([]auth.Permission, error) `perm:"read"`
|
||||
AuthNew func(ctx context.Context, perms []auth.Permission) ([]byte, error) `perm:"admin"`
|
||||
|
||||
NetConnectedness func(context.Context, peer.ID) (network.Connectedness, error) `perm:"read"`
|
||||
NetPeers func(context.Context) ([]peer.AddrInfo, error) `perm:"read"`
|
||||
NetConnect func(context.Context, peer.AddrInfo) error `perm:"write"`
|
||||
NetAddrsListen func(context.Context) (peer.AddrInfo, error) `perm:"read"`
|
||||
NetDisconnect func(context.Context, peer.ID) error `perm:"write"`
|
||||
NetFindPeer func(context.Context, peer.ID) (peer.AddrInfo, error) `perm:"read"`
|
||||
NetPubsubScores func(context.Context) ([]api.PubsubScore, error) `perm:"read"`
|
||||
NetConnectedness func(context.Context, peer.ID) (network.Connectedness, error) `perm:"read"`
|
||||
NetPeers func(context.Context) ([]peer.AddrInfo, error) `perm:"read"`
|
||||
NetConnect func(context.Context, peer.AddrInfo) error `perm:"write"`
|
||||
NetAddrsListen func(context.Context) (peer.AddrInfo, error) `perm:"read"`
|
||||
NetDisconnect func(context.Context, peer.ID) error `perm:"write"`
|
||||
NetFindPeer func(context.Context, peer.ID) (peer.AddrInfo, error) `perm:"read"`
|
||||
NetPubsubScores func(context.Context) ([]api.PubsubScore, error) `perm:"read"`
|
||||
NetAutoNatStatus func(context.Context) (api.NatInfo, error) `perm:"read"`
|
||||
NetBandwidthStats func(ctx context.Context) (metrics.Stats, error) `perm:"read"`
|
||||
NetBandwidthStatsByPeer func(ctx context.Context) (map[string]metrics.Stats, error) `perm:"read"`
|
||||
NetBandwidthStatsByProtocol func(ctx context.Context) (map[protocol.ID]metrics.Stats, error) `perm:"read"`
|
||||
NetAgentVersion func(ctx context.Context, p peer.ID) (string, error) `perm:"read"`
|
||||
|
||||
ID func(context.Context) (peer.ID, error) `perm:"read"`
|
||||
Version func(context.Context) (api.Version, error) `perm:"read"`
|
||||
@@ -60,38 +76,54 @@ type FullNodeStruct struct {
|
||||
CommonStruct
|
||||
|
||||
Internal struct {
|
||||
ChainNotify func(context.Context) (<-chan []*api.HeadChange, error) `perm:"read"`
|
||||
ChainHead func(context.Context) (*types.TipSet, error) `perm:"read"`
|
||||
ChainGetRandomness func(context.Context, types.TipSetKey, crypto.DomainSeparationTag, abi.ChainEpoch, []byte) (abi.Randomness, error) `perm:"read"`
|
||||
ChainGetBlock func(context.Context, cid.Cid) (*types.BlockHeader, error) `perm:"read"`
|
||||
ChainGetTipSet func(context.Context, types.TipSetKey) (*types.TipSet, error) `perm:"read"`
|
||||
ChainGetBlockMessages func(context.Context, cid.Cid) (*api.BlockMessages, error) `perm:"read"`
|
||||
ChainGetParentReceipts func(context.Context, cid.Cid) ([]*types.MessageReceipt, error) `perm:"read"`
|
||||
ChainGetParentMessages func(context.Context, cid.Cid) ([]api.Message, error) `perm:"read"`
|
||||
ChainGetTipSetByHeight func(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error) `perm:"read"`
|
||||
ChainReadObj func(context.Context, cid.Cid) ([]byte, error) `perm:"read"`
|
||||
ChainHasObj func(context.Context, cid.Cid) (bool, error) `perm:"read"`
|
||||
ChainStatObj func(context.Context, cid.Cid, cid.Cid) (api.ObjStat, error) `perm:"read"`
|
||||
ChainSetHead func(context.Context, types.TipSetKey) error `perm:"admin"`
|
||||
ChainGetGenesis func(context.Context) (*types.TipSet, error) `perm:"read"`
|
||||
ChainTipSetWeight func(context.Context, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
ChainGetNode func(ctx context.Context, p string) (*api.IpldObject, error) `perm:"read"`
|
||||
ChainGetMessage func(context.Context, cid.Cid) (*types.Message, error) `perm:"read"`
|
||||
ChainGetPath func(context.Context, types.TipSetKey, types.TipSetKey) ([]*api.HeadChange, error) `perm:"read"`
|
||||
ChainExport func(context.Context, types.TipSetKey) (<-chan []byte, error) `perm:"read"`
|
||||
ChainNotify func(context.Context) (<-chan []*api.HeadChange, error) `perm:"read"`
|
||||
ChainHead func(context.Context) (*types.TipSet, error) `perm:"read"`
|
||||
ChainGetRandomnessFromTickets func(context.Context, types.TipSetKey, crypto.DomainSeparationTag, abi.ChainEpoch, []byte) (abi.Randomness, error) `perm:"read"`
|
||||
ChainGetRandomnessFromBeacon func(context.Context, types.TipSetKey, crypto.DomainSeparationTag, abi.ChainEpoch, []byte) (abi.Randomness, error) `perm:"read"`
|
||||
ChainGetBlock func(context.Context, cid.Cid) (*types.BlockHeader, error) `perm:"read"`
|
||||
ChainGetTipSet func(context.Context, types.TipSetKey) (*types.TipSet, error) `perm:"read"`
|
||||
ChainGetBlockMessages func(context.Context, cid.Cid) (*api.BlockMessages, error) `perm:"read"`
|
||||
ChainGetParentReceipts func(context.Context, cid.Cid) ([]*types.MessageReceipt, error) `perm:"read"`
|
||||
ChainGetParentMessages func(context.Context, cid.Cid) ([]api.Message, error) `perm:"read"`
|
||||
ChainGetTipSetByHeight func(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error) `perm:"read"`
|
||||
ChainReadObj func(context.Context, cid.Cid) ([]byte, error) `perm:"read"`
|
||||
ChainHasObj func(context.Context, cid.Cid) (bool, error) `perm:"read"`
|
||||
ChainStatObj func(context.Context, cid.Cid, cid.Cid) (api.ObjStat, error) `perm:"read"`
|
||||
ChainSetHead func(context.Context, types.TipSetKey) error `perm:"admin"`
|
||||
ChainGetGenesis func(context.Context) (*types.TipSet, error) `perm:"read"`
|
||||
ChainTipSetWeight func(context.Context, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
ChainGetNode func(ctx context.Context, p string) (*api.IpldObject, error) `perm:"read"`
|
||||
ChainGetMessage func(context.Context, cid.Cid) (*types.Message, error) `perm:"read"`
|
||||
ChainGetPath func(context.Context, types.TipSetKey, types.TipSetKey) ([]*api.HeadChange, error) `perm:"read"`
|
||||
ChainExport func(context.Context, abi.ChainEpoch, types.TipSetKey) (<-chan []byte, error) `perm:"read"`
|
||||
|
||||
BeaconGetEntry func(ctx context.Context, epoch abi.ChainEpoch) (*types.BeaconEntry, error) `perm:"read"`
|
||||
|
||||
GasEstimateGasPremium func(context.Context, uint64, address.Address, int64, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
GasEstimateGasLimit func(context.Context, *types.Message, types.TipSetKey) (int64, error) `perm:"read"`
|
||||
GasEstimateFeeCap func(context.Context, *types.Message, int64, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
GasEstimateMessageGas func(context.Context, *types.Message, *api.MessageSendSpec, types.TipSetKey) (*types.Message, error) `perm:"read"`
|
||||
|
||||
SyncState func(context.Context) (*api.SyncState, error) `perm:"read"`
|
||||
SyncSubmitBlock func(ctx context.Context, blk *types.BlockMsg) error `perm:"write"`
|
||||
SyncIncomingBlocks func(ctx context.Context) (<-chan *types.BlockHeader, error) `perm:"read"`
|
||||
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"`
|
||||
SyncCheckBad func(ctx context.Context, bcid cid.Cid) (string, error) `perm:"read"`
|
||||
|
||||
MpoolPending func(context.Context, types.TipSetKey) ([]*types.SignedMessage, error) `perm:"read"`
|
||||
MpoolPush func(context.Context, *types.SignedMessage) (cid.Cid, error) `perm:"write"`
|
||||
MpoolPushMessage func(context.Context, *types.Message) (*types.SignedMessage, error) `perm:"sign"`
|
||||
MpoolGetNonce func(context.Context, address.Address) (uint64, error) `perm:"read"`
|
||||
MpoolSub func(context.Context) (<-chan api.MpoolUpdate, error) `perm:"read"`
|
||||
MpoolEstimateGasPrice func(context.Context, uint64, address.Address, int64, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
MpoolGetConfig func(context.Context) (*types.MpoolConfig, error) `perm:"read"`
|
||||
MpoolSetConfig func(context.Context, *types.MpoolConfig) error `perm:"write"`
|
||||
|
||||
MpoolSelect func(context.Context, types.TipSetKey, float64) ([]*types.SignedMessage, error) `perm:"read"`
|
||||
|
||||
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"`
|
||||
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"`
|
||||
|
||||
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"`
|
||||
@@ -109,78 +141,99 @@ type FullNodeStruct struct {
|
||||
WalletImport func(context.Context, *types.KeyInfo) (address.Address, error) `perm:"admin"`
|
||||
WalletDelete func(context.Context, address.Address) error `perm:"write"`
|
||||
|
||||
ClientImport func(ctx context.Context, ref api.FileRef) (cid.Cid, error) `perm:"admin"`
|
||||
ClientListImports func(ctx context.Context) ([]api.Import, error) `perm:"write"`
|
||||
ClientHasLocal func(ctx context.Context, root cid.Cid) (bool, error) `perm:"write"`
|
||||
ClientFindData func(ctx context.Context, root cid.Cid) ([]api.QueryOffer, error) `perm:"read"`
|
||||
ClientMinerQueryOffer func(ctx context.Context, root cid.Cid, miner address.Address) (api.QueryOffer, error) `perm:"read"`
|
||||
ClientStartDeal func(ctx context.Context, params *api.StartDealParams) (*cid.Cid, error) `perm:"admin"`
|
||||
ClientGetDealInfo func(context.Context, cid.Cid) (*api.DealInfo, error) `perm:"read"`
|
||||
ClientListDeals func(ctx context.Context) ([]api.DealInfo, error) `perm:"write"`
|
||||
ClientRetrieve func(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) error `perm:"admin"`
|
||||
ClientQueryAsk func(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.SignedStorageAsk, error) `perm:"read"`
|
||||
ClientCalcCommP func(ctx context.Context, inpath string, miner address.Address) (*api.CommPRet, error) `perm:"read"`
|
||||
ClientGenCar func(ctx context.Context, ref api.FileRef, outpath string) error `perm:"write"`
|
||||
ClientImport func(ctx context.Context, ref api.FileRef) (*api.ImportRes, error) `perm:"admin"`
|
||||
ClientListImports func(ctx context.Context) ([]api.Import, error) `perm:"write"`
|
||||
ClientRemoveImport func(ctx context.Context, importID multistore.StoreID) error `perm:"admin"`
|
||||
ClientHasLocal func(ctx context.Context, root cid.Cid) (bool, error) `perm:"write"`
|
||||
ClientFindData func(ctx context.Context, root cid.Cid, piece *cid.Cid) ([]api.QueryOffer, error) `perm:"read"`
|
||||
ClientMinerQueryOffer func(ctx context.Context, miner address.Address, root cid.Cid, piece *cid.Cid) (api.QueryOffer, error) `perm:"read"`
|
||||
ClientStartDeal func(ctx context.Context, params *api.StartDealParams) (*cid.Cid, error) `perm:"admin"`
|
||||
ClientGetDealInfo func(context.Context, cid.Cid) (*api.DealInfo, error) `perm:"read"`
|
||||
ClientListDeals func(ctx context.Context) ([]api.DealInfo, error) `perm:"write"`
|
||||
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"`
|
||||
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"`
|
||||
ClientRetrieveTryRestartInsufficientFunds func(ctx context.Context, paymentChannel address.Address) error `perm:"write"`
|
||||
|
||||
StateNetworkName func(context.Context) (dtypes.NetworkName, error) `perm:"read"`
|
||||
StateMinerSectors func(context.Context, address.Address, *abi.BitField, bool, types.TipSetKey) ([]*api.ChainSectorInfo, error) `perm:"read"`
|
||||
StateMinerProvingSet func(context.Context, address.Address, types.TipSetKey) ([]*api.ChainSectorInfo, error) `perm:"read"`
|
||||
StateMinerProvingDeadline func(context.Context, address.Address, types.TipSetKey) (*miner.DeadlineInfo, error) `perm:"read"`
|
||||
StateMinerPower func(context.Context, address.Address, types.TipSetKey) (*api.MinerPower, error) `perm:"read"`
|
||||
StateMinerInfo func(context.Context, address.Address, types.TipSetKey) (api.MinerInfo, error) `perm:"read"`
|
||||
StateMinerDeadlines func(context.Context, address.Address, types.TipSetKey) (*miner.Deadlines, error) `perm:"read"`
|
||||
StateMinerFaults func(context.Context, address.Address, types.TipSetKey) (*abi.BitField, error) `perm:"read"`
|
||||
StateAllMinerFaults func(context.Context, abi.ChainEpoch, types.TipSetKey) ([]*api.Fault, error) `perm:"read"`
|
||||
StateMinerRecoveries func(context.Context, address.Address, types.TipSetKey) (*abi.BitField, error) `perm:"read"`
|
||||
StateMinerInitialPledgeCollateral func(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
StateMinerAvailableBalance func(context.Context, address.Address, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
StateSectorPreCommitInfo func(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error) `perm:"read"`
|
||||
StateSectorGetInfo func(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorOnChainInfo, error) `perm:"read"`
|
||||
StateCall func(context.Context, *types.Message, types.TipSetKey) (*api.InvocResult, error) `perm:"read"`
|
||||
StateReplay func(context.Context, types.TipSetKey, cid.Cid) (*api.InvocResult, error) `perm:"read"`
|
||||
StateGetActor func(context.Context, address.Address, types.TipSetKey) (*types.Actor, error) `perm:"read"`
|
||||
StateReadState func(context.Context, address.Address, types.TipSetKey) (*api.ActorState, error) `perm:"read"`
|
||||
StatePledgeCollateral func(context.Context, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
StateWaitMsg func(ctx context.Context, cid cid.Cid, confidence uint64) (*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"`
|
||||
StateMarketBalance func(context.Context, address.Address, types.TipSetKey) (api.MarketBalance, error) `perm:"read"`
|
||||
StateMarketParticipants func(context.Context, types.TipSetKey) (map[string]api.MarketBalance, error) `perm:"read"`
|
||||
StateMarketDeals func(context.Context, types.TipSetKey) (map[string]api.MarketDeal, error) `perm:"read"`
|
||||
StateMarketStorageDeal func(context.Context, abi.DealID, types.TipSetKey) (*api.MarketDeal, error) `perm:"read"`
|
||||
StateLookupID func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) `perm:"read"`
|
||||
StateAccountKey func(context.Context, address.Address, types.TipSetKey) (address.Address, error) `perm:"read"`
|
||||
StateChangedActors func(context.Context, cid.Cid, cid.Cid) (map[string]types.Actor, error) `perm:"read"`
|
||||
StateGetReceipt func(context.Context, cid.Cid, types.TipSetKey) (*types.MessageReceipt, error) `perm:"read"`
|
||||
StateMinerSectorCount func(context.Context, address.Address, types.TipSetKey) (api.MinerSectors, error) `perm:"read"`
|
||||
StateListMessages func(ctx context.Context, match *types.Message, tsk types.TipSetKey, toht abi.ChainEpoch) ([]cid.Cid, error) `perm:"read"`
|
||||
StateCompute func(context.Context, abi.ChainEpoch, []*types.Message, types.TipSetKey) (*api.ComputeStateOutput, error) `perm:"read"`
|
||||
StateNetworkName func(context.Context) (dtypes.NetworkName, error) `perm:"read"`
|
||||
StateMinerSectors func(context.Context, address.Address, *bitfield.BitField, bool, types.TipSetKey) ([]*api.ChainSectorInfo, error) `perm:"read"`
|
||||
StateMinerActiveSectors func(context.Context, address.Address, types.TipSetKey) ([]*api.ChainSectorInfo, error) `perm:"read"`
|
||||
StateMinerProvingDeadline func(context.Context, address.Address, types.TipSetKey) (*dline.Info, error) `perm:"read"`
|
||||
StateMinerPower func(context.Context, address.Address, types.TipSetKey) (*api.MinerPower, error) `perm:"read"`
|
||||
StateMinerInfo func(context.Context, address.Address, types.TipSetKey) (api.MinerInfo, error) `perm:"read"`
|
||||
StateMinerDeadlines func(context.Context, address.Address, types.TipSetKey) ([]*miner.Deadline, error) `perm:"read"`
|
||||
StateMinerPartitions func(context.Context, address.Address, uint64, types.TipSetKey) ([]*miner.Partition, error) `perm:"read"`
|
||||
StateMinerFaults func(context.Context, address.Address, types.TipSetKey) (bitfield.BitField, error) `perm:"read"`
|
||||
StateAllMinerFaults func(context.Context, abi.ChainEpoch, types.TipSetKey) ([]*api.Fault, error) `perm:"read"`
|
||||
StateMinerRecoveries func(context.Context, address.Address, types.TipSetKey) (bitfield.BitField, error) `perm:"read"`
|
||||
StateMinerPreCommitDepositForPower func(context.Context, address.Address, miner.SectorPreCommitInfo, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
StateMinerInitialPledgeCollateral func(context.Context, address.Address, miner.SectorPreCommitInfo, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
StateMinerAvailableBalance func(context.Context, address.Address, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
StateSectorPreCommitInfo func(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error) `perm:"read"`
|
||||
StateSectorGetInfo func(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorOnChainInfo, error) `perm:"read"`
|
||||
StateSectorExpiration func(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*api.SectorExpiration, error) `perm:"read"`
|
||||
StateSectorPartition func(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*api.SectorLocation, error) `perm:"read"`
|
||||
StateCall func(context.Context, *types.Message, types.TipSetKey) (*api.InvocResult, error) `perm:"read"`
|
||||
StateReplay func(context.Context, types.TipSetKey, cid.Cid) (*api.InvocResult, error) `perm:"read"`
|
||||
StateGetActor func(context.Context, address.Address, types.TipSetKey) (*types.Actor, error) `perm:"read"`
|
||||
StateReadState func(context.Context, address.Address, types.TipSetKey) (*api.ActorState, error) `perm:"read"`
|
||||
StateWaitMsg func(ctx context.Context, cid cid.Cid, confidence uint64) (*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"`
|
||||
StateMarketBalance func(context.Context, address.Address, types.TipSetKey) (api.MarketBalance, error) `perm:"read"`
|
||||
StateMarketParticipants func(context.Context, types.TipSetKey) (map[string]api.MarketBalance, error) `perm:"read"`
|
||||
StateMarketDeals func(context.Context, types.TipSetKey) (map[string]api.MarketDeal, error) `perm:"read"`
|
||||
StateMarketStorageDeal func(context.Context, abi.DealID, types.TipSetKey) (*api.MarketDeal, error) `perm:"read"`
|
||||
StateLookupID func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) `perm:"read"`
|
||||
StateAccountKey func(context.Context, address.Address, types.TipSetKey) (address.Address, error) `perm:"read"`
|
||||
StateChangedActors func(context.Context, cid.Cid, cid.Cid) (map[string]types.Actor, error) `perm:"read"`
|
||||
StateGetReceipt func(context.Context, cid.Cid, types.TipSetKey) (*types.MessageReceipt, error) `perm:"read"`
|
||||
StateMinerSectorCount func(context.Context, address.Address, types.TipSetKey) (api.MinerSectors, error) `perm:"read"`
|
||||
StateListMessages func(ctx context.Context, match *types.Message, tsk types.TipSetKey, toht abi.ChainEpoch) ([]cid.Cid, error) `perm:"read"`
|
||||
StateCompute func(context.Context, abi.ChainEpoch, []*types.Message, types.TipSetKey) (*api.ComputeStateOutput, error) `perm:"read"`
|
||||
StateVerifiedClientStatus func(context.Context, address.Address, types.TipSetKey) (*verifreg.DataCap, 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"`
|
||||
|
||||
MsigGetAvailableBalance func(context.Context, address.Address, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
MsigCreate func(context.Context, int64, []address.Address, abi.ChainEpoch, types.BigInt, address.Address, types.BigInt) (cid.Cid, error) `perm:"sign"`
|
||||
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"`
|
||||
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"`
|
||||
MsigAddCancel func(context.Context, address.Address, address.Address, uint64, address.Address, bool) (cid.Cid, error) `perm:"sign"`
|
||||
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"`
|
||||
|
||||
MarketEnsureAvailable func(context.Context, address.Address, address.Address, types.BigInt) (cid.Cid, error) `perm:"sign"`
|
||||
|
||||
PaychGet func(ctx context.Context, from, to address.Address, ensureFunds types.BigInt) (*api.ChannelInfo, error) `perm:"sign"`
|
||||
PaychList func(context.Context) ([]address.Address, error) `perm:"read"`
|
||||
PaychStatus func(context.Context, address.Address) (*api.PaychStatus, error) `perm:"read"`
|
||||
PaychClose func(context.Context, address.Address) (cid.Cid, error) `perm:"sign"`
|
||||
PaychAllocateLane func(context.Context, address.Address) (uint64, error) `perm:"sign"`
|
||||
PaychNewPayment func(ctx context.Context, from, to address.Address, vouchers []api.VoucherSpec) (*api.PaymentInfo, error) `perm:"sign"`
|
||||
PaychVoucherCheck func(context.Context, *paych.SignedVoucher) error `perm:"read"`
|
||||
PaychVoucherCheckValid func(context.Context, address.Address, *paych.SignedVoucher) error `perm:"read"`
|
||||
PaychVoucherCheckSpendable func(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (bool, error) `perm:"read"`
|
||||
PaychVoucherAdd func(context.Context, address.Address, *paych.SignedVoucher, []byte, types.BigInt) (types.BigInt, error) `perm:"write"`
|
||||
PaychVoucherCreate func(context.Context, address.Address, big.Int, uint64) (*paych.SignedVoucher, error) `perm:"sign"`
|
||||
PaychVoucherList func(context.Context, address.Address) ([]*paych.SignedVoucher, error) `perm:"write"`
|
||||
PaychVoucherSubmit func(context.Context, address.Address, *paych.SignedVoucher) (cid.Cid, error) `perm:"sign"`
|
||||
PaychGet func(ctx context.Context, from, to address.Address, amt types.BigInt) (*api.ChannelInfo, error) `perm:"sign"`
|
||||
PaychGetWaitReady func(context.Context, cid.Cid) (address.Address, error) `perm:"sign"`
|
||||
PaychAvailableFunds func(address.Address) (*api.ChannelAvailableFunds, error) `perm:"sign"`
|
||||
PaychAvailableFundsByFromTo func(address.Address, address.Address) (*api.ChannelAvailableFunds, error) `perm:"sign"`
|
||||
PaychList func(context.Context) ([]address.Address, error) `perm:"read"`
|
||||
PaychStatus func(context.Context, address.Address) (*api.PaychStatus, error) `perm:"read"`
|
||||
PaychSettle func(context.Context, address.Address) (cid.Cid, error) `perm:"sign"`
|
||||
PaychCollect func(context.Context, address.Address) (cid.Cid, error) `perm:"sign"`
|
||||
PaychAllocateLane func(context.Context, address.Address) (uint64, error) `perm:"sign"`
|
||||
PaychNewPayment func(ctx context.Context, from, to address.Address, vouchers []api.VoucherSpec) (*api.PaymentInfo, error) `perm:"sign"`
|
||||
PaychVoucherCheck func(context.Context, *paych.SignedVoucher) error `perm:"read"`
|
||||
PaychVoucherCheckValid func(context.Context, address.Address, *paych.SignedVoucher) error `perm:"read"`
|
||||
PaychVoucherCheckSpendable func(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (bool, error) `perm:"read"`
|
||||
PaychVoucherAdd func(context.Context, address.Address, *paych.SignedVoucher, []byte, types.BigInt) (types.BigInt, error) `perm:"write"`
|
||||
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"`
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,30 +250,45 @@ type StorageMinerStruct struct {
|
||||
|
||||
MiningBase func(context.Context) (*types.TipSet, error) `perm:"read"`
|
||||
|
||||
MarketImportDealData func(context.Context, cid.Cid, string) error `perm:"write"`
|
||||
MarketListDeals func(ctx context.Context) ([]storagemarket.StorageDeal, error) `perm:"read"`
|
||||
MarketListIncompleteDeals func(ctx context.Context) ([]storagemarket.MinerDeal, error) `perm:"read"`
|
||||
MarketSetAsk func(ctx context.Context, price types.BigInt, duration abi.ChainEpoch, minPieceSize abi.PaddedPieceSize, maxPieceSize abi.PaddedPieceSize) error `perm:"admin"`
|
||||
MarketGetAsk func(ctx context.Context) (*storagemarket.SignedStorageAsk, error) `perm:"read"`
|
||||
MarketImportDealData func(context.Context, cid.Cid, string) error `perm:"write"`
|
||||
MarketListDeals func(ctx context.Context) ([]storagemarket.StorageDeal, error) `perm:"read"`
|
||||
MarketListRetrievalDeals func(ctx context.Context) ([]retrievalmarket.ProviderDealState, error) `perm:"read"`
|
||||
MarketGetDealUpdates func(ctx context.Context) (<-chan storagemarket.MinerDeal, error) `perm:"read"`
|
||||
MarketListIncompleteDeals func(ctx context.Context) ([]storagemarket.MinerDeal, error) `perm:"read"`
|
||||
MarketSetAsk func(ctx context.Context, price types.BigInt, verifiedPrice types.BigInt, duration abi.ChainEpoch, minPieceSize abi.PaddedPieceSize, maxPieceSize abi.PaddedPieceSize) error `perm:"admin"`
|
||||
MarketGetAsk func(ctx context.Context) (*storagemarket.SignedStorageAsk, error) `perm:"read"`
|
||||
MarketSetRetrievalAsk func(ctx context.Context, rask *retrievalmarket.Ask) error `perm:"admin"`
|
||||
MarketGetRetrievalAsk func(ctx context.Context) (*retrievalmarket.Ask, error) `perm:"read"`
|
||||
MarketListDataTransfers func(ctx context.Context) ([]api.DataTransferChannel, error) `perm:"write"`
|
||||
MarketDataTransferUpdates func(ctx context.Context) (<-chan api.DataTransferChannel, error) `perm:"write"`
|
||||
|
||||
PledgeSector func(context.Context) error `perm:"write"`
|
||||
|
||||
SectorsStatus func(context.Context, abi.SectorNumber) (api.SectorInfo, error) `perm:"read"`
|
||||
SectorsList func(context.Context) ([]abi.SectorNumber, error) `perm:"read"`
|
||||
SectorsRefs func(context.Context) (map[string][]api.SealedRef, error) `perm:"read"`
|
||||
SectorsUpdate func(context.Context, abi.SectorNumber, api.SectorState) error `perm:"write"`
|
||||
SectorRemove func(context.Context, abi.SectorNumber) error `perm:"admin"`
|
||||
SectorsStatus func(ctx context.Context, sid abi.SectorNumber, showOnChainInfo bool) (api.SectorInfo, error) `perm:"read"`
|
||||
SectorsList func(context.Context) ([]abi.SectorNumber, error) `perm:"read"`
|
||||
SectorsRefs func(context.Context) (map[string][]api.SealedRef, error) `perm:"read"`
|
||||
SectorStartSealing func(context.Context, abi.SectorNumber) error `perm:"write"`
|
||||
SectorSetSealDelay func(context.Context, time.Duration) error `perm:"write"`
|
||||
SectorGetSealDelay func(context.Context) (time.Duration, error) `perm:"read"`
|
||||
SectorSetExpectedSealDuration func(context.Context, time.Duration) error `perm:"write"`
|
||||
SectorGetExpectedSealDuration func(context.Context) (time.Duration, error) `perm:"read"`
|
||||
SectorsUpdate func(context.Context, abi.SectorNumber, api.SectorState) error `perm:"admin"`
|
||||
SectorRemove func(context.Context, abi.SectorNumber) error `perm:"admin"`
|
||||
SectorMarkForUpgrade func(ctx context.Context, id abi.SectorNumber) error `perm:"admin"`
|
||||
|
||||
WorkerConnect func(context.Context, string) error `perm:"admin"` // TODO: worker perm
|
||||
WorkerStats func(context.Context) (map[uint64]storiface.WorkerStats, error) `perm:"admin"`
|
||||
WorkerJobs func(context.Context) (map[uint64][]storiface.WorkerJob, error) `perm:"admin"`
|
||||
|
||||
SealingSchedDiag func(context.Context) (interface{}, error) `perm:"admin"`
|
||||
|
||||
StorageList func(context.Context) (map[stores.ID][]stores.Decl, error) `perm:"admin"`
|
||||
StorageLocal func(context.Context) (map[stores.ID]string, error) `perm:"admin"`
|
||||
StorageStat func(context.Context, stores.ID) (stores.FsStat, error) `perm:"admin"`
|
||||
StorageAttach func(context.Context, stores.StorageInfo, stores.FsStat) error `perm:"admin"`
|
||||
StorageStat func(context.Context, stores.ID) (fsutil.FsStat, error) `perm:"admin"`
|
||||
StorageAttach func(context.Context, stores.StorageInfo, fsutil.FsStat) error `perm:"admin"`
|
||||
StorageDeclareSector func(context.Context, stores.ID, abi.SectorID, stores.SectorFileType, bool) error `perm:"admin"`
|
||||
StorageDropSector func(context.Context, stores.ID, abi.SectorID, stores.SectorFileType) error `perm:"admin"`
|
||||
StorageFindSector func(context.Context, abi.SectorID, stores.SectorFileType, bool) ([]stores.SectorStorageInfo, error) `perm:"admin"`
|
||||
StorageFindSector func(context.Context, abi.SectorID, stores.SectorFileType, abi.RegisteredSealProof, bool) ([]stores.SectorStorageInfo, error) `perm:"admin"`
|
||||
StorageInfo func(context.Context, stores.ID) (stores.StorageInfo, error) `perm:"admin"`
|
||||
StorageBestAlloc func(ctx context.Context, allocate stores.SectorFileType, spt abi.RegisteredSealProof, sealing stores.PathType) ([]stores.StorageInfo, error) `perm:"admin"`
|
||||
StorageReportHealth func(ctx context.Context, id stores.ID, report stores.HealthReport) error `perm:"admin"`
|
||||
@@ -241,6 +309,11 @@ type StorageMinerStruct struct {
|
||||
DealsSetPieceCidBlocklist func(context.Context, []cid.Cid) error `perm:"admin"`
|
||||
|
||||
StorageAddLocal func(ctx context.Context, path string) error `perm:"admin"`
|
||||
|
||||
PiecesListPieces func(ctx context.Context) ([]cid.Cid, error) `perm:"read"`
|
||||
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"`
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,6 +327,7 @@ type WorkerStruct struct {
|
||||
Paths func(context.Context) ([]stores.StoragePath, error) `perm:"admin"`
|
||||
Info func(context.Context) (storiface.WorkerInfo, error) `perm:"admin"`
|
||||
|
||||
AddPiece func(ctx context.Context, sector abi.SectorID, pieceSizes []abi.UnpaddedPieceSize, newPieceSize abi.UnpaddedPieceSize, pieceData storage.Data) (abi.PieceInfo, error) `perm:"admin"`
|
||||
SealPreCommit1 func(ctx context.Context, sector abi.SectorID, ticket abi.SealRandomness, pieces []abi.PieceInfo) (storage.PreCommit1Out, error) `perm:"admin"`
|
||||
SealPreCommit2 func(context.Context, abi.SectorID, storage.PreCommit1Out) (cids storage.SectorCids, err error) `perm:"admin"`
|
||||
SealCommit1 func(ctx context.Context, sector abi.SectorID, ticket abi.SealRandomness, seed abi.InteractiveSealRandomness, pieces []abi.PieceInfo, cids storage.SectorCids) (storage.Commit1Out, error) `perm:"admin"`
|
||||
@@ -261,10 +335,11 @@ type WorkerStruct struct {
|
||||
FinalizeSector func(context.Context, abi.SectorID, []storage.Range) error `perm:"admin"`
|
||||
ReleaseUnsealed func(ctx context.Context, sector abi.SectorID, safeToFree []storage.Range) error `perm:"admin"`
|
||||
Remove func(ctx context.Context, sector abi.SectorID) error `perm:"admin"`
|
||||
MoveStorage func(ctx context.Context, sector abi.SectorID) error `perm:"admin"`
|
||||
MoveStorage func(ctx context.Context, sector abi.SectorID, types stores.SectorFileType) error `perm:"admin"`
|
||||
StorageAddLocal func(ctx context.Context, path string) error `perm:"admin"`
|
||||
|
||||
UnsealPiece func(context.Context, abi.SectorID, storiface.UnpaddedByteIndex, abi.UnpaddedPieceSize, abi.SealRandomness, cid.Cid) error `perm:"admin"`
|
||||
ReadPiece func(context.Context, io.Writer, abi.SectorID, storiface.UnpaddedByteIndex, abi.UnpaddedPieceSize) error `perm:"admin"`
|
||||
ReadPiece func(context.Context, io.Writer, abi.SectorID, storiface.UnpaddedByteIndex, abi.UnpaddedPieceSize) (bool, error) `perm:"admin"`
|
||||
|
||||
Fetch func(context.Context, abi.SectorID, stores.SectorFileType, stores.PathType, stores.AcquireMode) error `perm:"admin"`
|
||||
|
||||
@@ -285,6 +360,7 @@ func (c *CommonStruct) AuthNew(ctx context.Context, perms []auth.Permission) ([]
|
||||
func (c *CommonStruct) NetPubsubScores(ctx context.Context) ([]api.PubsubScore, error) {
|
||||
return c.Internal.NetPubsubScores(ctx)
|
||||
}
|
||||
|
||||
func (c *CommonStruct) NetConnectedness(ctx context.Context, pid peer.ID) (network.Connectedness, error) {
|
||||
return c.Internal.NetConnectedness(ctx, pid)
|
||||
}
|
||||
@@ -309,6 +385,26 @@ func (c *CommonStruct) NetFindPeer(ctx context.Context, p peer.ID) (peer.AddrInf
|
||||
return c.Internal.NetFindPeer(ctx, p)
|
||||
}
|
||||
|
||||
func (c *CommonStruct) NetAutoNatStatus(ctx context.Context) (api.NatInfo, error) {
|
||||
return c.Internal.NetAutoNatStatus(ctx)
|
||||
}
|
||||
|
||||
func (c *CommonStruct) NetBandwidthStats(ctx context.Context) (metrics.Stats, error) {
|
||||
return c.Internal.NetBandwidthStats(ctx)
|
||||
}
|
||||
|
||||
func (c *CommonStruct) NetBandwidthStatsByPeer(ctx context.Context) (map[string]metrics.Stats, error) {
|
||||
return c.Internal.NetBandwidthStatsByPeer(ctx)
|
||||
}
|
||||
|
||||
func (c *CommonStruct) NetBandwidthStatsByProtocol(ctx context.Context) (map[protocol.ID]metrics.Stats, error) {
|
||||
return c.Internal.NetBandwidthStatsByProtocol(ctx)
|
||||
}
|
||||
|
||||
func (c *CommonStruct) NetAgentVersion(ctx context.Context, p peer.ID) (string, error) {
|
||||
return c.Internal.NetAgentVersion(ctx, p)
|
||||
}
|
||||
|
||||
// ID implements API.ID
|
||||
func (c *CommonStruct) ID(ctx context.Context) (peer.ID, error) {
|
||||
return c.Internal.ID(ctx)
|
||||
@@ -341,7 +437,11 @@ func (c *FullNodeStruct) ClientListImports(ctx context.Context) ([]api.Import, e
|
||||
return c.Internal.ClientListImports(ctx)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ClientImport(ctx context.Context, ref api.FileRef) (cid.Cid, error) {
|
||||
func (c *FullNodeStruct) ClientRemoveImport(ctx context.Context, importID multistore.StoreID) error {
|
||||
return c.Internal.ClientRemoveImport(ctx, importID)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ClientImport(ctx context.Context, ref api.FileRef) (*api.ImportRes, error) {
|
||||
return c.Internal.ClientImport(ctx, ref)
|
||||
}
|
||||
|
||||
@@ -349,17 +449,18 @@ func (c *FullNodeStruct) ClientHasLocal(ctx context.Context, root cid.Cid) (bool
|
||||
return c.Internal.ClientHasLocal(ctx, root)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ClientFindData(ctx context.Context, root cid.Cid) ([]api.QueryOffer, error) {
|
||||
return c.Internal.ClientFindData(ctx, root)
|
||||
func (c *FullNodeStruct) ClientFindData(ctx context.Context, root cid.Cid, piece *cid.Cid) ([]api.QueryOffer, error) {
|
||||
return c.Internal.ClientFindData(ctx, root, piece)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ClientMinerQueryOffer(ctx context.Context, root cid.Cid, miner address.Address) (api.QueryOffer, error) {
|
||||
return c.Internal.ClientMinerQueryOffer(ctx, root, miner)
|
||||
func (c *FullNodeStruct) ClientMinerQueryOffer(ctx context.Context, miner address.Address, root cid.Cid, piece *cid.Cid) (api.QueryOffer, error) {
|
||||
return c.Internal.ClientMinerQueryOffer(ctx, miner, root, piece)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ClientStartDeal(ctx context.Context, params *api.StartDealParams) (*cid.Cid, error) {
|
||||
return c.Internal.ClientStartDeal(ctx, params)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ClientGetDealInfo(ctx context.Context, deal cid.Cid) (*api.DealInfo, error) {
|
||||
return c.Internal.ClientGetDealInfo(ctx, deal)
|
||||
}
|
||||
@@ -368,41 +469,93 @@ func (c *FullNodeStruct) ClientListDeals(ctx context.Context) ([]api.DealInfo, e
|
||||
return c.Internal.ClientListDeals(ctx)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ClientGetDealUpdates(ctx context.Context) (<-chan api.DealInfo, error) {
|
||||
return c.Internal.ClientGetDealUpdates(ctx)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ClientRetrieve(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) error {
|
||||
return c.Internal.ClientRetrieve(ctx, order, ref)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ClientRetrieveWithEvents(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) (<-chan marketevents.RetrievalEvent, error) {
|
||||
return c.Internal.ClientRetrieveWithEvents(ctx, order, ref)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ClientQueryAsk(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.SignedStorageAsk, error) {
|
||||
return c.Internal.ClientQueryAsk(ctx, p, miner)
|
||||
}
|
||||
func (c *FullNodeStruct) ClientCalcCommP(ctx context.Context, inpath string, miner address.Address) (*api.CommPRet, error) {
|
||||
return c.Internal.ClientCalcCommP(ctx, inpath, miner)
|
||||
func (c *FullNodeStruct) ClientCalcCommP(ctx context.Context, inpath string) (*api.CommPRet, error) {
|
||||
return c.Internal.ClientCalcCommP(ctx, inpath)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ClientGenCar(ctx context.Context, ref api.FileRef, outpath string) error {
|
||||
return c.Internal.ClientGenCar(ctx, ref, outpath)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ClientDealSize(ctx context.Context, root cid.Cid) (api.DataSize, error) {
|
||||
return c.Internal.ClientDealSize(ctx, root)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ClientListDataTransfers(ctx context.Context) ([]api.DataTransferChannel, error) {
|
||||
return c.Internal.ClientListDataTransfers(ctx)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ClientDataTransferUpdates(ctx context.Context) (<-chan api.DataTransferChannel, error) {
|
||||
return c.Internal.ClientDataTransferUpdates(ctx)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ClientRetrieveTryRestartInsufficientFunds(ctx context.Context, paymentChannel address.Address) error {
|
||||
return c.Internal.ClientRetrieveTryRestartInsufficientFunds(ctx, paymentChannel)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) GasEstimateGasPremium(ctx context.Context, nblocksincl uint64, sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error) {
|
||||
return c.Internal.GasEstimateGasPremium(ctx, nblocksincl, sender, gaslimit, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) GasEstimateFeeCap(ctx context.Context, msg *types.Message, maxqueueblks int64, tsk types.TipSetKey) (types.BigInt, error) {
|
||||
return c.Internal.GasEstimateFeeCap(ctx, msg, maxqueueblks, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error) {
|
||||
return c.Internal.GasEstimateMessageGas(ctx, msg, spec, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) GasEstimateGasLimit(ctx context.Context, msg *types.Message, tsk types.TipSetKey) (int64, error) {
|
||||
return c.Internal.GasEstimateGasLimit(ctx, msg, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MpoolGetConfig(ctx context.Context) (*types.MpoolConfig, error) {
|
||||
return c.Internal.MpoolGetConfig(ctx)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MpoolSetConfig(ctx context.Context, cfg *types.MpoolConfig) error {
|
||||
return c.Internal.MpoolSetConfig(ctx, cfg)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MpoolSelect(ctx context.Context, tsk types.TipSetKey, tq float64) ([]*types.SignedMessage, error) {
|
||||
return c.Internal.MpoolSelect(ctx, tsk, tq)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MpoolPending(ctx context.Context, tsk types.TipSetKey) ([]*types.SignedMessage, error) {
|
||||
return c.Internal.MpoolPending(ctx, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MpoolClear(ctx context.Context, local bool) error {
|
||||
return c.Internal.MpoolClear(ctx, local)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MpoolPush(ctx context.Context, smsg *types.SignedMessage) (cid.Cid, error) {
|
||||
return c.Internal.MpoolPush(ctx, smsg)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MpoolPushMessage(ctx context.Context, msg *types.Message) (*types.SignedMessage, error) {
|
||||
return c.Internal.MpoolPushMessage(ctx, msg)
|
||||
func (c *FullNodeStruct) MpoolPushMessage(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec) (*types.SignedMessage, error) {
|
||||
return c.Internal.MpoolPushMessage(ctx, msg, spec)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MpoolSub(ctx context.Context) (<-chan api.MpoolUpdate, error) {
|
||||
return c.Internal.MpoolSub(ctx)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MpoolEstimateGasPrice(ctx context.Context, nblocksincl uint64, sender address.Address, limit int64, tsk types.TipSetKey) (types.BigInt, error) {
|
||||
return c.Internal.MpoolEstimateGasPrice(ctx, nblocksincl, sender, limit, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MinerGetBaseInfo(ctx context.Context, maddr address.Address, epoch abi.ChainEpoch, tsk types.TipSetKey) (*api.MiningBaseInfo, error) {
|
||||
return c.Internal.MinerGetBaseInfo(ctx, maddr, epoch, tsk)
|
||||
}
|
||||
@@ -415,8 +568,12 @@ func (c *FullNodeStruct) ChainHead(ctx context.Context) (*types.TipSet, error) {
|
||||
return c.Internal.ChainHead(ctx)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ChainGetRandomness(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error) {
|
||||
return c.Internal.ChainGetRandomness(ctx, tsk, personalization, randEpoch, entropy)
|
||||
func (c *FullNodeStruct) ChainGetRandomnessFromTickets(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error) {
|
||||
return c.Internal.ChainGetRandomnessFromTickets(ctx, tsk, personalization, randEpoch, entropy)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ChainGetRandomnessFromBeacon(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error) {
|
||||
return c.Internal.ChainGetRandomnessFromBeacon(ctx, tsk, personalization, randEpoch, entropy)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error) {
|
||||
@@ -535,8 +692,12 @@ func (c *FullNodeStruct) ChainGetPath(ctx context.Context, from types.TipSetKey,
|
||||
return c.Internal.ChainGetPath(ctx, from, to)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ChainExport(ctx context.Context, tsk types.TipSetKey) (<-chan []byte, error) {
|
||||
return c.Internal.ChainExport(ctx, tsk)
|
||||
func (c *FullNodeStruct) ChainExport(ctx context.Context, nroots abi.ChainEpoch, tsk types.TipSetKey) (<-chan []byte, error) {
|
||||
return c.Internal.ChainExport(ctx, nroots, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) BeaconGetEntry(ctx context.Context, epoch abi.ChainEpoch) (*types.BeaconEntry, error) {
|
||||
return c.Internal.BeaconGetEntry(ctx, epoch)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) SyncState(ctx context.Context) (*api.SyncState, error) {
|
||||
@@ -551,10 +712,18 @@ func (c *FullNodeStruct) SyncIncomingBlocks(ctx context.Context) (<-chan *types.
|
||||
return c.Internal.SyncIncomingBlocks(ctx)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) SyncCheckpoint(ctx context.Context, tsk types.TipSetKey) error {
|
||||
return c.Internal.SyncCheckpoint(ctx, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) SyncMarkBad(ctx context.Context, bcid cid.Cid) error {
|
||||
return c.Internal.SyncMarkBad(ctx, bcid)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) SyncUnmarkBad(ctx context.Context, bcid cid.Cid) error {
|
||||
return c.Internal.SyncUnmarkBad(ctx, bcid)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) SyncCheckBad(ctx context.Context, bcid cid.Cid) (string, error) {
|
||||
return c.Internal.SyncCheckBad(ctx, bcid)
|
||||
}
|
||||
@@ -563,15 +732,15 @@ func (c *FullNodeStruct) StateNetworkName(ctx context.Context) (dtypes.NetworkNa
|
||||
return c.Internal.StateNetworkName(ctx)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerSectors(ctx context.Context, addr address.Address, filter *abi.BitField, filterOut bool, tsk types.TipSetKey) ([]*api.ChainSectorInfo, error) {
|
||||
func (c *FullNodeStruct) StateMinerSectors(ctx context.Context, addr address.Address, filter *bitfield.BitField, filterOut bool, tsk types.TipSetKey) ([]*api.ChainSectorInfo, error) {
|
||||
return c.Internal.StateMinerSectors(ctx, addr, filter, filterOut, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerProvingSet(ctx context.Context, addr address.Address, tsk types.TipSetKey) ([]*api.ChainSectorInfo, error) {
|
||||
return c.Internal.StateMinerProvingSet(ctx, addr, tsk)
|
||||
func (c *FullNodeStruct) StateMinerActiveSectors(ctx context.Context, addr address.Address, tsk types.TipSetKey) ([]*api.ChainSectorInfo, error) {
|
||||
return c.Internal.StateMinerActiveSectors(ctx, addr, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerProvingDeadline(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*miner.DeadlineInfo, error) {
|
||||
func (c *FullNodeStruct) StateMinerProvingDeadline(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*dline.Info, error) {
|
||||
return c.Internal.StateMinerProvingDeadline(ctx, addr, tsk)
|
||||
}
|
||||
|
||||
@@ -583,11 +752,15 @@ func (c *FullNodeStruct) StateMinerInfo(ctx context.Context, actor address.Addre
|
||||
return c.Internal.StateMinerInfo(ctx, actor, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerDeadlines(ctx context.Context, m address.Address, tsk types.TipSetKey) (*miner.Deadlines, error) {
|
||||
func (c *FullNodeStruct) StateMinerDeadlines(ctx context.Context, m address.Address, tsk types.TipSetKey) ([]*miner.Deadline, error) {
|
||||
return c.Internal.StateMinerDeadlines(ctx, m, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerFaults(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*abi.BitField, error) {
|
||||
func (c *FullNodeStruct) StateMinerPartitions(ctx context.Context, m address.Address, dlIdx uint64, tsk types.TipSetKey) ([]*miner.Partition, error) {
|
||||
return c.Internal.StateMinerPartitions(ctx, m, dlIdx, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerFaults(ctx context.Context, actor address.Address, tsk types.TipSetKey) (bitfield.BitField, error) {
|
||||
return c.Internal.StateMinerFaults(ctx, actor, tsk)
|
||||
}
|
||||
|
||||
@@ -595,12 +768,16 @@ func (c *FullNodeStruct) StateAllMinerFaults(ctx context.Context, cutoff abi.Cha
|
||||
return c.Internal.StateAllMinerFaults(ctx, cutoff, endTsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerRecoveries(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*abi.BitField, error) {
|
||||
func (c *FullNodeStruct) StateMinerRecoveries(ctx context.Context, actor address.Address, tsk types.TipSetKey) (bitfield.BitField, error) {
|
||||
return c.Internal.StateMinerRecoveries(ctx, actor, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerInitialPledgeCollateral(ctx context.Context, maddr address.Address, snum abi.SectorNumber, tsk types.TipSetKey) (types.BigInt, error) {
|
||||
return c.Internal.StateMinerInitialPledgeCollateral(ctx, maddr, snum, tsk)
|
||||
func (c *FullNodeStruct) StateMinerPreCommitDepositForPower(ctx context.Context, maddr address.Address, pci miner.SectorPreCommitInfo, tsk types.TipSetKey) (types.BigInt, error) {
|
||||
return c.Internal.StateMinerPreCommitDepositForPower(ctx, maddr, pci, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerInitialPledgeCollateral(ctx context.Context, maddr address.Address, pci miner.SectorPreCommitInfo, tsk types.TipSetKey) (types.BigInt, error) {
|
||||
return c.Internal.StateMinerInitialPledgeCollateral(ctx, maddr, pci, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerAvailableBalance(ctx context.Context, maddr address.Address, tsk types.TipSetKey) (types.BigInt, error) {
|
||||
@@ -615,6 +792,14 @@ func (c *FullNodeStruct) StateSectorGetInfo(ctx context.Context, maddr address.A
|
||||
return c.Internal.StateSectorGetInfo(ctx, maddr, n, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateSectorExpiration(ctx context.Context, maddr address.Address, n abi.SectorNumber, tsk types.TipSetKey) (*api.SectorExpiration, error) {
|
||||
return c.Internal.StateSectorExpiration(ctx, maddr, n, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok types.TipSetKey) (*api.SectorLocation, error) {
|
||||
return c.Internal.StateSectorPartition(ctx, maddr, sectorNumber, tok)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateCall(ctx context.Context, msg *types.Message, tsk types.TipSetKey) (*api.InvocResult, error) {
|
||||
return c.Internal.StateCall(ctx, msg, tsk)
|
||||
}
|
||||
@@ -631,10 +816,6 @@ func (c *FullNodeStruct) StateReadState(ctx context.Context, addr address.Addres
|
||||
return c.Internal.StateReadState(ctx, addr, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StatePledgeCollateral(ctx context.Context, tsk types.TipSetKey) (types.BigInt, error) {
|
||||
return c.Internal.StatePledgeCollateral(ctx, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateWaitMsg(ctx context.Context, msgc cid.Cid, confidence uint64) (*api.MsgLookup, error) {
|
||||
return c.Internal.StateWaitMsg(ctx, msgc, confidence)
|
||||
}
|
||||
@@ -691,11 +872,27 @@ func (c *FullNodeStruct) StateCompute(ctx context.Context, height abi.ChainEpoch
|
||||
return c.Internal.StateCompute(ctx, height, msgs, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateVerifiedClientStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*verifreg.DataCap, error) {
|
||||
return c.Internal.StateVerifiedClientStatus(ctx, addr, 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) {
|
||||
return c.Internal.StateCirculatingSupply(ctx, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigGetAvailableBalance(ctx context.Context, a address.Address, tsk types.TipSetKey) (types.BigInt, error) {
|
||||
return c.Internal.MsigGetAvailableBalance(ctx, a, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigCreate(ctx context.Context, req int64, addrs []address.Address, duration abi.ChainEpoch, val types.BigInt, src address.Address, gp types.BigInt) (cid.Cid, error) {
|
||||
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)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigCreate(ctx context.Context, req uint64, addrs []address.Address, duration abi.ChainEpoch, val types.BigInt, src address.Address, gp types.BigInt) (cid.Cid, error) {
|
||||
return c.Internal.MsigCreate(ctx, req, addrs, duration, val, src, gp)
|
||||
}
|
||||
|
||||
@@ -711,6 +908,18 @@ func (c *FullNodeStruct) MsigCancel(ctx context.Context, msig address.Address, t
|
||||
return c.Internal.MsigCancel(ctx, msig, txID, to, amt, src, method, params)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigAddPropose(ctx context.Context, msig address.Address, src address.Address, newAdd address.Address, inc bool) (cid.Cid, error) {
|
||||
return c.Internal.MsigAddPropose(ctx, msig, src, newAdd, inc)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigAddApprove(ctx context.Context, msig address.Address, src address.Address, txID uint64, proposer address.Address, newAdd address.Address, inc bool) (cid.Cid, error) {
|
||||
return c.Internal.MsigAddApprove(ctx, msig, src, txID, proposer, newAdd, inc)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigAddCancel(ctx context.Context, msig address.Address, src address.Address, txID uint64, newAdd address.Address, inc bool) (cid.Cid, error) {
|
||||
return c.Internal.MsigAddCancel(ctx, msig, src, txID, newAdd, inc)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigSwapPropose(ctx context.Context, msig address.Address, src address.Address, oldAdd address.Address, newAdd address.Address) (cid.Cid, error) {
|
||||
return c.Internal.MsigSwapPropose(ctx, msig, src, oldAdd, newAdd)
|
||||
}
|
||||
@@ -727,8 +936,20 @@ func (c *FullNodeStruct) MarketEnsureAvailable(ctx context.Context, addr, wallet
|
||||
return c.Internal.MarketEnsureAvailable(ctx, addr, wallet, amt)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) PaychGet(ctx context.Context, from, to address.Address, ensureFunds types.BigInt) (*api.ChannelInfo, error) {
|
||||
return c.Internal.PaychGet(ctx, from, to, ensureFunds)
|
||||
func (c *FullNodeStruct) PaychGet(ctx context.Context, from, to address.Address, amt types.BigInt) (*api.ChannelInfo, error) {
|
||||
return c.Internal.PaychGet(ctx, from, to, amt)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) PaychGetWaitReady(ctx context.Context, sentinel cid.Cid) (address.Address, error) {
|
||||
return c.Internal.PaychGetWaitReady(ctx, sentinel)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) PaychAvailableFunds(ch address.Address) (*api.ChannelAvailableFunds, error) {
|
||||
return c.Internal.PaychAvailableFunds(ch)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) PaychAvailableFundsByFromTo(from, to address.Address) (*api.ChannelAvailableFunds, error) {
|
||||
return c.Internal.PaychAvailableFundsByFromTo(from, to)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) PaychList(ctx context.Context) ([]address.Address, error) {
|
||||
@@ -751,7 +972,7 @@ func (c *FullNodeStruct) PaychVoucherAdd(ctx context.Context, addr address.Addre
|
||||
return c.Internal.PaychVoucherAdd(ctx, addr, sv, proof, minDelta)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) PaychVoucherCreate(ctx context.Context, pch address.Address, amt types.BigInt, lane uint64) (*paych.SignedVoucher, error) {
|
||||
func (c *FullNodeStruct) PaychVoucherCreate(ctx context.Context, pch address.Address, amt types.BigInt, lane uint64) (*api.VoucherCreateResult, error) {
|
||||
return c.Internal.PaychVoucherCreate(ctx, pch, amt, lane)
|
||||
}
|
||||
|
||||
@@ -759,8 +980,12 @@ func (c *FullNodeStruct) PaychVoucherList(ctx context.Context, pch address.Addre
|
||||
return c.Internal.PaychVoucherList(ctx, pch)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) PaychClose(ctx context.Context, a address.Address) (cid.Cid, error) {
|
||||
return c.Internal.PaychClose(ctx, a)
|
||||
func (c *FullNodeStruct) PaychSettle(ctx context.Context, a address.Address) (cid.Cid, error) {
|
||||
return c.Internal.PaychSettle(ctx, a)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) PaychCollect(ctx context.Context, a address.Address) (cid.Cid, error) {
|
||||
return c.Internal.PaychCollect(ctx, a)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) PaychAllocateLane(ctx context.Context, ch address.Address) (uint64, error) {
|
||||
@@ -771,8 +996,8 @@ func (c *FullNodeStruct) PaychNewPayment(ctx context.Context, from, to address.A
|
||||
return c.Internal.PaychNewPayment(ctx, from, to, vouchers)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) PaychVoucherSubmit(ctx context.Context, ch address.Address, sv *paych.SignedVoucher) (cid.Cid, error) {
|
||||
return c.Internal.PaychVoucherSubmit(ctx, ch, sv)
|
||||
func (c *FullNodeStruct) PaychVoucherSubmit(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, secret []byte, proof []byte) (cid.Cid, error) {
|
||||
return c.Internal.PaychVoucherSubmit(ctx, ch, sv, secret, proof)
|
||||
}
|
||||
|
||||
// StorageMinerStruct
|
||||
@@ -794,8 +1019,8 @@ func (c *StorageMinerStruct) PledgeSector(ctx context.Context) error {
|
||||
}
|
||||
|
||||
// Get the status of a given sector by ID
|
||||
func (c *StorageMinerStruct) SectorsStatus(ctx context.Context, sid abi.SectorNumber) (api.SectorInfo, error) {
|
||||
return c.Internal.SectorsStatus(ctx, sid)
|
||||
func (c *StorageMinerStruct) SectorsStatus(ctx context.Context, sid abi.SectorNumber, showOnChainInfo bool) (api.SectorInfo, error) {
|
||||
return c.Internal.SectorsStatus(ctx, sid, showOnChainInfo)
|
||||
}
|
||||
|
||||
// List all staged sectors
|
||||
@@ -807,6 +1032,26 @@ func (c *StorageMinerStruct) SectorsRefs(ctx context.Context) (map[string][]api.
|
||||
return c.Internal.SectorsRefs(ctx)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) SectorStartSealing(ctx context.Context, number abi.SectorNumber) error {
|
||||
return c.Internal.SectorStartSealing(ctx, number)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) SectorSetSealDelay(ctx context.Context, delay time.Duration) error {
|
||||
return c.Internal.SectorSetSealDelay(ctx, delay)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) SectorGetSealDelay(ctx context.Context) (time.Duration, error) {
|
||||
return c.Internal.SectorGetSealDelay(ctx)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) SectorSetExpectedSealDuration(ctx context.Context, delay time.Duration) error {
|
||||
return c.Internal.SectorSetExpectedSealDuration(ctx, delay)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) SectorGetExpectedSealDuration(ctx context.Context) (time.Duration, error) {
|
||||
return c.Internal.SectorGetExpectedSealDuration(ctx)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) SectorsUpdate(ctx context.Context, id abi.SectorNumber, state api.SectorState) error {
|
||||
return c.Internal.SectorsUpdate(ctx, id, state)
|
||||
}
|
||||
@@ -815,6 +1060,10 @@ func (c *StorageMinerStruct) SectorRemove(ctx context.Context, number abi.Sector
|
||||
return c.Internal.SectorRemove(ctx, number)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) SectorMarkForUpgrade(ctx context.Context, number abi.SectorNumber) error {
|
||||
return c.Internal.SectorMarkForUpgrade(ctx, number)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) WorkerConnect(ctx context.Context, url string) error {
|
||||
return c.Internal.WorkerConnect(ctx, url)
|
||||
}
|
||||
@@ -823,7 +1072,15 @@ func (c *StorageMinerStruct) WorkerStats(ctx context.Context) (map[uint64]storif
|
||||
return c.Internal.WorkerStats(ctx)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) StorageAttach(ctx context.Context, si stores.StorageInfo, st stores.FsStat) error {
|
||||
func (c *StorageMinerStruct) WorkerJobs(ctx context.Context) (map[uint64][]storiface.WorkerJob, error) {
|
||||
return c.Internal.WorkerJobs(ctx)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) SealingSchedDiag(ctx context.Context) (interface{}, error) {
|
||||
return c.Internal.SealingSchedDiag(ctx)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) StorageAttach(ctx context.Context, si stores.StorageInfo, st fsutil.FsStat) error {
|
||||
return c.Internal.StorageAttach(ctx, si, st)
|
||||
}
|
||||
|
||||
@@ -835,8 +1092,8 @@ func (c *StorageMinerStruct) StorageDropSector(ctx context.Context, storageId st
|
||||
return c.Internal.StorageDropSector(ctx, storageId, s, ft)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) StorageFindSector(ctx context.Context, si abi.SectorID, types stores.SectorFileType, allowFetch bool) ([]stores.SectorStorageInfo, error) {
|
||||
return c.Internal.StorageFindSector(ctx, si, types, allowFetch)
|
||||
func (c *StorageMinerStruct) StorageFindSector(ctx context.Context, si abi.SectorID, types stores.SectorFileType, spt abi.RegisteredSealProof, allowFetch bool) ([]stores.SectorStorageInfo, error) {
|
||||
return c.Internal.StorageFindSector(ctx, si, types, spt, allowFetch)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) StorageList(ctx context.Context) (map[stores.ID][]stores.Decl, error) {
|
||||
@@ -847,7 +1104,7 @@ func (c *StorageMinerStruct) StorageLocal(ctx context.Context) (map[stores.ID]st
|
||||
return c.Internal.StorageLocal(ctx)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) StorageStat(ctx context.Context, id stores.ID) (stores.FsStat, error) {
|
||||
func (c *StorageMinerStruct) StorageStat(ctx context.Context, id stores.ID) (fsutil.FsStat, error) {
|
||||
return c.Internal.StorageStat(ctx, id)
|
||||
}
|
||||
|
||||
@@ -879,18 +1136,42 @@ func (c *StorageMinerStruct) MarketListDeals(ctx context.Context) ([]storagemark
|
||||
return c.Internal.MarketListDeals(ctx)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) MarketListRetrievalDeals(ctx context.Context) ([]retrievalmarket.ProviderDealState, error) {
|
||||
return c.Internal.MarketListRetrievalDeals(ctx)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) MarketGetDealUpdates(ctx context.Context) (<-chan storagemarket.MinerDeal, error) {
|
||||
return c.Internal.MarketGetDealUpdates(ctx)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) MarketListIncompleteDeals(ctx context.Context) ([]storagemarket.MinerDeal, error) {
|
||||
return c.Internal.MarketListIncompleteDeals(ctx)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) MarketSetAsk(ctx context.Context, price types.BigInt, duration abi.ChainEpoch, minPieceSize abi.PaddedPieceSize, maxPieceSize abi.PaddedPieceSize) error {
|
||||
return c.Internal.MarketSetAsk(ctx, price, duration, minPieceSize, maxPieceSize)
|
||||
func (c *StorageMinerStruct) MarketSetAsk(ctx context.Context, price types.BigInt, verifiedPrice types.BigInt, duration abi.ChainEpoch, minPieceSize abi.PaddedPieceSize, maxPieceSize abi.PaddedPieceSize) error {
|
||||
return c.Internal.MarketSetAsk(ctx, price, verifiedPrice, duration, minPieceSize, maxPieceSize)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) MarketGetAsk(ctx context.Context) (*storagemarket.SignedStorageAsk, error) {
|
||||
return c.Internal.MarketGetAsk(ctx)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) MarketSetRetrievalAsk(ctx context.Context, rask *retrievalmarket.Ask) error {
|
||||
return c.Internal.MarketSetRetrievalAsk(ctx, rask)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) MarketGetRetrievalAsk(ctx context.Context) (*retrievalmarket.Ask, error) {
|
||||
return c.Internal.MarketGetRetrievalAsk(ctx)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) MarketListDataTransfers(ctx context.Context) ([]api.DataTransferChannel, error) {
|
||||
return c.Internal.MarketListDataTransfers(ctx)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) MarketDataTransferUpdates(ctx context.Context) (<-chan api.DataTransferChannel, error) {
|
||||
return c.Internal.MarketDataTransferUpdates(ctx)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) DealsImportData(ctx context.Context, dealPropCid cid.Cid, file string) error {
|
||||
return c.Internal.DealsImportData(ctx, dealPropCid, file)
|
||||
}
|
||||
@@ -943,6 +1224,22 @@ func (c *StorageMinerStruct) StorageAddLocal(ctx context.Context, path string) e
|
||||
return c.Internal.StorageAddLocal(ctx, path)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) PiecesListPieces(ctx context.Context) ([]cid.Cid, error) {
|
||||
return c.Internal.PiecesListPieces(ctx)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) PiecesListCidInfos(ctx context.Context) ([]cid.Cid, error) {
|
||||
return c.Internal.PiecesListCidInfos(ctx)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) PiecesGetPieceInfo(ctx context.Context, pieceCid cid.Cid) (*piecestore.PieceInfo, error) {
|
||||
return c.Internal.PiecesGetPieceInfo(ctx, pieceCid)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) PiecesGetCIDInfo(ctx context.Context, payloadCid cid.Cid) (*piecestore.CIDInfo, error) {
|
||||
return c.Internal.PiecesGetCIDInfo(ctx, payloadCid)
|
||||
}
|
||||
|
||||
// WorkerStruct
|
||||
|
||||
func (w *WorkerStruct) Version(ctx context.Context) (build.Version, error) {
|
||||
@@ -961,6 +1258,10 @@ func (w *WorkerStruct) Info(ctx context.Context) (storiface.WorkerInfo, error) {
|
||||
return w.Internal.Info(ctx)
|
||||
}
|
||||
|
||||
func (w *WorkerStruct) AddPiece(ctx context.Context, sector abi.SectorID, pieceSizes []abi.UnpaddedPieceSize, newPieceSize abi.UnpaddedPieceSize, pieceData storage.Data) (abi.PieceInfo, error) {
|
||||
return w.Internal.AddPiece(ctx, sector, pieceSizes, newPieceSize, pieceData)
|
||||
}
|
||||
|
||||
func (w *WorkerStruct) SealPreCommit1(ctx context.Context, sector abi.SectorID, ticket abi.SealRandomness, pieces []abi.PieceInfo) (storage.PreCommit1Out, error) {
|
||||
return w.Internal.SealPreCommit1(ctx, sector, ticket, pieces)
|
||||
}
|
||||
@@ -989,15 +1290,19 @@ func (w *WorkerStruct) Remove(ctx context.Context, sector abi.SectorID) error {
|
||||
return w.Internal.Remove(ctx, sector)
|
||||
}
|
||||
|
||||
func (w *WorkerStruct) MoveStorage(ctx context.Context, sector abi.SectorID) error {
|
||||
return w.Internal.MoveStorage(ctx, sector)
|
||||
func (w *WorkerStruct) MoveStorage(ctx context.Context, sector abi.SectorID, types stores.SectorFileType) error {
|
||||
return w.Internal.MoveStorage(ctx, sector, types)
|
||||
}
|
||||
|
||||
func (w *WorkerStruct) StorageAddLocal(ctx context.Context, path string) error {
|
||||
return w.Internal.StorageAddLocal(ctx, path)
|
||||
}
|
||||
|
||||
func (w *WorkerStruct) UnsealPiece(ctx context.Context, id abi.SectorID, index storiface.UnpaddedByteIndex, size abi.UnpaddedPieceSize, randomness abi.SealRandomness, c cid.Cid) error {
|
||||
return w.Internal.UnsealPiece(ctx, id, index, size, randomness, c)
|
||||
}
|
||||
|
||||
func (w *WorkerStruct) ReadPiece(ctx context.Context, writer io.Writer, id abi.SectorID, index storiface.UnpaddedByteIndex, size abi.UnpaddedPieceSize) error {
|
||||
func (w *WorkerStruct) ReadPiece(ctx context.Context, writer io.Writer, id abi.SectorID, index storiface.UnpaddedByteIndex, size abi.UnpaddedPieceSize) (bool, error) {
|
||||
return w.Internal.ReadPiece(ctx, writer, id, index, size)
|
||||
}
|
||||
|
||||
|
||||
+51
-51
@@ -6,8 +6,8 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||
abi "github.com/filecoin-project/go-state-types/abi"
|
||||
paych "github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
xerrors "golang.org/x/xerrors"
|
||||
)
|
||||
@@ -33,7 +33,7 @@ func (t *PaymentInfo) MarshalCBOR(w io.Writer) error {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("Channel"))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.WriteString(w, "Channel"); err != nil {
|
||||
if _, err := io.WriteString(w, string("Channel")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -41,26 +41,20 @@ func (t *PaymentInfo) MarshalCBOR(w io.Writer) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.ChannelMessage (cid.Cid) (struct)
|
||||
if len("ChannelMessage") > cbg.MaxLength {
|
||||
return xerrors.Errorf("Value in field \"ChannelMessage\" was too long")
|
||||
// t.WaitSentinel (cid.Cid) (struct)
|
||||
if len("WaitSentinel") > cbg.MaxLength {
|
||||
return xerrors.Errorf("Value in field \"WaitSentinel\" was too long")
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("ChannelMessage"))); err != nil {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("WaitSentinel"))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.WriteString(w, "ChannelMessage"); err != nil {
|
||||
if _, err := io.WriteString(w, string("WaitSentinel")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if t.ChannelMessage == nil {
|
||||
if _, err := w.Write(cbg.CborNull); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := cbg.WriteCidBuf(scratch, w, *t.ChannelMessage); err != nil {
|
||||
return xerrors.Errorf("failed to write cid field t.ChannelMessage: %w", err)
|
||||
}
|
||||
if err := cbg.WriteCidBuf(scratch, w, t.WaitSentinel); err != nil {
|
||||
return xerrors.Errorf("failed to write cid field t.WaitSentinel: %w", err)
|
||||
}
|
||||
|
||||
// t.Vouchers ([]*paych.SignedVoucher) (slice)
|
||||
@@ -71,7 +65,7 @@ func (t *PaymentInfo) MarshalCBOR(w io.Writer) error {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("Vouchers"))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.WriteString(w, "Vouchers"); err != nil {
|
||||
if _, err := io.WriteString(w, string("Vouchers")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -91,6 +85,8 @@ func (t *PaymentInfo) MarshalCBOR(w io.Writer) error {
|
||||
}
|
||||
|
||||
func (t *PaymentInfo) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = PaymentInfo{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
@@ -131,29 +127,17 @@ func (t *PaymentInfo) UnmarshalCBOR(r io.Reader) error {
|
||||
}
|
||||
|
||||
}
|
||||
// t.ChannelMessage (cid.Cid) (struct)
|
||||
case "ChannelMessage":
|
||||
// t.WaitSentinel (cid.Cid) (struct)
|
||||
case "WaitSentinel":
|
||||
|
||||
{
|
||||
|
||||
pb, err := br.PeekByte()
|
||||
c, err := cbg.ReadCid(br)
|
||||
if err != nil {
|
||||
return err
|
||||
return xerrors.Errorf("failed to read cid field t.WaitSentinel: %w", err)
|
||||
}
|
||||
if pb == cbg.CborNull[0] {
|
||||
var nbuf [1]byte
|
||||
if _, err := br.Read(nbuf[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
|
||||
c, err := cbg.ReadCid(br)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to read cid field t.ChannelMessage: %w", err)
|
||||
}
|
||||
|
||||
t.ChannelMessage = &c
|
||||
}
|
||||
t.WaitSentinel = c
|
||||
|
||||
}
|
||||
// t.Vouchers ([]*paych.SignedVoucher) (slice)
|
||||
@@ -212,7 +196,7 @@ func (t *SealedRef) MarshalCBOR(w io.Writer) error {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("SectorID"))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.WriteString(w, "SectorID"); err != nil {
|
||||
if _, err := io.WriteString(w, string("SectorID")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -220,7 +204,7 @@ func (t *SealedRef) MarshalCBOR(w io.Writer) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.Offset (uint64) (uint64)
|
||||
// t.Offset (abi.PaddedPieceSize) (uint64)
|
||||
if len("Offset") > cbg.MaxLength {
|
||||
return xerrors.Errorf("Value in field \"Offset\" was too long")
|
||||
}
|
||||
@@ -228,7 +212,7 @@ func (t *SealedRef) MarshalCBOR(w io.Writer) error {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("Offset"))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.WriteString(w, "Offset"); err != nil {
|
||||
if _, err := io.WriteString(w, string("Offset")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -244,7 +228,7 @@ func (t *SealedRef) MarshalCBOR(w io.Writer) error {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("Size"))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.WriteString(w, "Size"); err != nil {
|
||||
if _, err := io.WriteString(w, string("Size")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -256,6 +240,8 @@ func (t *SealedRef) MarshalCBOR(w io.Writer) error {
|
||||
}
|
||||
|
||||
func (t *SealedRef) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = SealedRef{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
@@ -301,7 +287,7 @@ func (t *SealedRef) UnmarshalCBOR(r io.Reader) error {
|
||||
t.SectorID = abi.SectorNumber(extra)
|
||||
|
||||
}
|
||||
// t.Offset (uint64) (uint64)
|
||||
// t.Offset (abi.PaddedPieceSize) (uint64)
|
||||
case "Offset":
|
||||
|
||||
{
|
||||
@@ -313,7 +299,7 @@ func (t *SealedRef) UnmarshalCBOR(r io.Reader) error {
|
||||
if maj != cbg.MajUnsignedInt {
|
||||
return fmt.Errorf("wrong type for uint64 field")
|
||||
}
|
||||
t.Offset = uint64(extra)
|
||||
t.Offset = abi.PaddedPieceSize(extra)
|
||||
|
||||
}
|
||||
// t.Size (abi.UnpaddedPieceSize) (uint64)
|
||||
@@ -358,7 +344,7 @@ func (t *SealedRefs) MarshalCBOR(w io.Writer) error {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("Refs"))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.WriteString(w, "Refs"); err != nil {
|
||||
if _, err := io.WriteString(w, string("Refs")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -378,6 +364,8 @@ func (t *SealedRefs) MarshalCBOR(w io.Writer) error {
|
||||
}
|
||||
|
||||
func (t *SealedRefs) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = SealedRefs{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
@@ -464,7 +452,7 @@ func (t *SealTicket) MarshalCBOR(w io.Writer) error {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("Value"))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.WriteString(w, "Value"); err != nil {
|
||||
if _, err := io.WriteString(w, string("Value")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -476,7 +464,7 @@ func (t *SealTicket) MarshalCBOR(w io.Writer) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := w.Write(t.Value); err != nil {
|
||||
if _, err := w.Write(t.Value[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -488,7 +476,7 @@ func (t *SealTicket) MarshalCBOR(w io.Writer) error {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("Epoch"))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.WriteString(w, "Epoch"); err != nil {
|
||||
if _, err := io.WriteString(w, string("Epoch")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -505,6 +493,8 @@ func (t *SealTicket) MarshalCBOR(w io.Writer) error {
|
||||
}
|
||||
|
||||
func (t *SealTicket) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = SealTicket{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
@@ -549,8 +539,12 @@ func (t *SealTicket) UnmarshalCBOR(r io.Reader) error {
|
||||
if maj != cbg.MajByteString {
|
||||
return fmt.Errorf("expected byte array")
|
||||
}
|
||||
t.Value = make([]byte, extra)
|
||||
if _, err := io.ReadFull(br, t.Value); err != nil {
|
||||
|
||||
if extra > 0 {
|
||||
t.Value = make([]uint8, extra)
|
||||
}
|
||||
|
||||
if _, err := io.ReadFull(br, t.Value[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
// t.Epoch (abi.ChainEpoch) (int64)
|
||||
@@ -606,7 +600,7 @@ func (t *SealSeed) MarshalCBOR(w io.Writer) error {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("Value"))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.WriteString(w, "Value"); err != nil {
|
||||
if _, err := io.WriteString(w, string("Value")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -618,7 +612,7 @@ func (t *SealSeed) MarshalCBOR(w io.Writer) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := w.Write(t.Value); err != nil {
|
||||
if _, err := w.Write(t.Value[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -630,7 +624,7 @@ func (t *SealSeed) MarshalCBOR(w io.Writer) error {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("Epoch"))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.WriteString(w, "Epoch"); err != nil {
|
||||
if _, err := io.WriteString(w, string("Epoch")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -647,6 +641,8 @@ func (t *SealSeed) MarshalCBOR(w io.Writer) error {
|
||||
}
|
||||
|
||||
func (t *SealSeed) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = SealSeed{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
@@ -691,8 +687,12 @@ func (t *SealSeed) UnmarshalCBOR(r io.Reader) error {
|
||||
if maj != cbg.MajByteString {
|
||||
return fmt.Errorf("expected byte array")
|
||||
}
|
||||
t.Value = make([]byte, extra)
|
||||
if _, err := io.ReadFull(br, t.Value); err != nil {
|
||||
|
||||
if extra > 0 {
|
||||
t.Value = make([]uint8, extra)
|
||||
}
|
||||
|
||||
if _, err := io.ReadFull(br, t.Value[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
// t.Epoch (abi.ChainEpoch) (int64)
|
||||
|
||||
+32
-9
@@ -1,18 +1,23 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-jsonrpc"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/api/apistruct"
|
||||
"github.com/filecoin-project/lotus/lib/rpcenc"
|
||||
)
|
||||
|
||||
// NewCommonRPC creates a new http jsonrpc client.
|
||||
func NewCommonRPC(addr string, requestHeader http.Header) (api.Common, jsonrpc.ClientCloser, error) {
|
||||
func NewCommonRPC(ctx context.Context, addr string, requestHeader http.Header) (api.Common, jsonrpc.ClientCloser, error) {
|
||||
var res apistruct.CommonStruct
|
||||
closer, err := jsonrpc.NewMergeClient(addr, "Filecoin",
|
||||
closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin",
|
||||
[]interface{}{
|
||||
&res.Internal,
|
||||
},
|
||||
@@ -23,9 +28,9 @@ func NewCommonRPC(addr string, requestHeader http.Header) (api.Common, jsonrpc.C
|
||||
}
|
||||
|
||||
// NewFullNodeRPC creates a new http jsonrpc client.
|
||||
func NewFullNodeRPC(addr string, requestHeader http.Header) (api.FullNode, jsonrpc.ClientCloser, error) {
|
||||
func NewFullNodeRPC(ctx context.Context, addr string, requestHeader http.Header) (api.FullNode, jsonrpc.ClientCloser, error) {
|
||||
var res apistruct.FullNodeStruct
|
||||
closer, err := jsonrpc.NewMergeClient(addr, "Filecoin",
|
||||
closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin",
|
||||
[]interface{}{
|
||||
&res.CommonStruct.Internal,
|
||||
&res.Internal,
|
||||
@@ -34,27 +39,45 @@ func NewFullNodeRPC(addr string, requestHeader http.Header) (api.FullNode, jsonr
|
||||
return &res, closer, err
|
||||
}
|
||||
|
||||
// NewStorageMinerRPC creates a new http jsonrpc client for storage miner
|
||||
func NewStorageMinerRPC(addr string, requestHeader http.Header) (api.StorageMiner, jsonrpc.ClientCloser, error) {
|
||||
// NewStorageMinerRPC creates a new http jsonrpc client for miner
|
||||
func NewStorageMinerRPC(ctx context.Context, addr string, requestHeader http.Header, opts ...jsonrpc.Option) (api.StorageMiner, jsonrpc.ClientCloser, error) {
|
||||
var res apistruct.StorageMinerStruct
|
||||
closer, err := jsonrpc.NewMergeClient(addr, "Filecoin",
|
||||
closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin",
|
||||
[]interface{}{
|
||||
&res.CommonStruct.Internal,
|
||||
&res.Internal,
|
||||
},
|
||||
requestHeader,
|
||||
opts...,
|
||||
)
|
||||
|
||||
return &res, closer, err
|
||||
}
|
||||
|
||||
func NewWorkerRPC(addr string, requestHeader http.Header) (api.WorkerAPI, jsonrpc.ClientCloser, error) {
|
||||
func NewWorkerRPC(ctx context.Context, addr string, requestHeader http.Header) (api.WorkerAPI, jsonrpc.ClientCloser, error) {
|
||||
u, err := url.Parse(addr)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
switch u.Scheme {
|
||||
case "ws":
|
||||
u.Scheme = "http"
|
||||
case "wss":
|
||||
u.Scheme = "https"
|
||||
}
|
||||
///rpc/v0 -> /rpc/streams/v0/push
|
||||
|
||||
u.Path = path.Join(u.Path, "../streams/v0/push")
|
||||
|
||||
var res apistruct.WorkerStruct
|
||||
closer, err := jsonrpc.NewMergeClient(addr, "Filecoin",
|
||||
closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin",
|
||||
[]interface{}{
|
||||
&res.Internal,
|
||||
},
|
||||
requestHeader,
|
||||
rpcenc.ReaderParamEncoder(u.String()),
|
||||
jsonrpc.WithNoReconnect(),
|
||||
jsonrpc.WithTimeout(30*time.Second),
|
||||
)
|
||||
|
||||
return &res, closer, err
|
||||
|
||||
+50
-10
@@ -12,22 +12,31 @@ import (
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-filestore"
|
||||
metrics "github.com/libp2p/go-libp2p-core/metrics"
|
||||
"github.com/libp2p/go-libp2p-core/network"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
protocol "github.com/libp2p/go-libp2p-core/protocol"
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-bitfield"
|
||||
datatransfer "github.com/filecoin-project/go-data-transfer"
|
||||
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
||||
"github.com/filecoin-project/go-jsonrpc/auth"
|
||||
"github.com/filecoin-project/go-multistore"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/go-state-types/exitcode"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/api/apistruct"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-filestore"
|
||||
"github.com/libp2p/go-libp2p-core/network"
|
||||
peer "github.com/libp2p/go-libp2p-peer"
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
)
|
||||
|
||||
var ExampleValues = map[reflect.Type]interface{}{
|
||||
@@ -66,11 +75,12 @@ func init() {
|
||||
|
||||
ExampleValues[reflect.TypeOf(addr)] = addr
|
||||
|
||||
pid, err := peer.IDB58Decode("12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf")
|
||||
pid, err := peer.Decode("12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
addExample(pid)
|
||||
addExample(&pid)
|
||||
|
||||
addExample(bitfield.NewFromSet([]uint64{5}))
|
||||
addExample(abi.RegisteredSealProof_StackedDrg32GiBV1)
|
||||
@@ -95,9 +105,15 @@ func init() {
|
||||
addExample(network.Connected)
|
||||
addExample(dtypes.NetworkName("lotus"))
|
||||
addExample(api.SyncStateStage(1))
|
||||
addExample(build.APIVersion)
|
||||
addExample(build.FullAPIVersion)
|
||||
addExample(api.PCHInbound)
|
||||
addExample(time.Minute)
|
||||
addExample(datatransfer.TransferID(3))
|
||||
addExample(datatransfer.Ongoing)
|
||||
addExample(multistore.StoreID(50))
|
||||
addExample(retrievalmarket.ClientEventDealAccepted)
|
||||
addExample(retrievalmarket.DealStatusNew)
|
||||
addExample(network.ReachabilityPublic)
|
||||
addExample(&types.ExecutionTrace{
|
||||
Msg: exampleValue(reflect.TypeOf(&types.Message{}), nil).(*types.Message),
|
||||
MsgRct: exampleValue(reflect.TypeOf(&types.MessageReceipt{}), nil).(*types.MessageReceipt),
|
||||
@@ -111,6 +127,30 @@ func init() {
|
||||
addExample(map[string]api.MarketBalance{
|
||||
"t026363": exampleValue(reflect.TypeOf(api.MarketBalance{}), nil).(api.MarketBalance),
|
||||
})
|
||||
addExample(map[string]*pubsub.TopicScoreSnapshot{
|
||||
"/blocks": {
|
||||
TimeInMesh: time.Minute,
|
||||
FirstMessageDeliveries: 122,
|
||||
MeshMessageDeliveries: 1234,
|
||||
InvalidMessageDeliveries: 3,
|
||||
},
|
||||
})
|
||||
addExample(map[string]metrics.Stats{
|
||||
"12D3KooWSXmXLJmBR1M7i9RW9GQPNUhZSzXKzxDHWtAgNuJAbyEJ": {
|
||||
RateIn: 100,
|
||||
RateOut: 50,
|
||||
TotalIn: 174000,
|
||||
TotalOut: 12500,
|
||||
},
|
||||
})
|
||||
addExample(map[protocol.ID]metrics.Stats{
|
||||
"/fil/hello/1.0.0": {
|
||||
RateIn: 100,
|
||||
RateOut: 50,
|
||||
TotalIn: 174000,
|
||||
TotalOut: 12500,
|
||||
},
|
||||
})
|
||||
|
||||
maddr, err := multiaddr.NewMultiaddr("/ip4/52.36.61.156/tcp/1347/p2p/12D3KooWFETiESTf1v4PGUvtnxMAcEFMzLZbJGg4tjWfGEimYior")
|
||||
if err != nil {
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/miner"
|
||||
)
|
||||
|
||||
type BlockMiner struct {
|
||||
ctx context.Context
|
||||
t *testing.T
|
||||
miner TestStorageNode
|
||||
blocktime time.Duration
|
||||
mine int64
|
||||
nulls int64
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
func NewBlockMiner(ctx context.Context, t *testing.T, miner TestStorageNode, blocktime time.Duration) *BlockMiner {
|
||||
return &BlockMiner{
|
||||
ctx: ctx,
|
||||
t: t,
|
||||
miner: miner,
|
||||
blocktime: blocktime,
|
||||
mine: int64(1),
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (bm *BlockMiner) MineBlocks() {
|
||||
time.Sleep(time.Second)
|
||||
go func() {
|
||||
defer close(bm.done)
|
||||
for atomic.LoadInt64(&bm.mine) == 1 {
|
||||
time.Sleep(bm.blocktime)
|
||||
nulls := atomic.SwapInt64(&bm.nulls, 0)
|
||||
if err := bm.miner.MineOne(bm.ctx, miner.MineReq{
|
||||
InjectNulls: abi.ChainEpoch(nulls),
|
||||
Done: func(bool, abi.ChainEpoch, error) {},
|
||||
}); err != nil {
|
||||
bm.t.Error(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (bm *BlockMiner) Stop() {
|
||||
atomic.AddInt64(&bm.mine, -1)
|
||||
fmt.Println("shutting down mining")
|
||||
<-bm.done
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/node/impl"
|
||||
)
|
||||
|
||||
func TestCCUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, 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)
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
|
||||
mine := int64(1)
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer close(done)
|
||||
for atomic.LoadInt64(&mine) == 1 {
|
||||
time.Sleep(blocktime)
|
||||
if err := sn[0].MineOne(ctx, MineNext); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
maddr, err := miner.ActorAddress(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
CC := abi.SectorNumber(GenesisPreseals + 1)
|
||||
Upgraded := CC + 1
|
||||
|
||||
pledgeSectors(t, ctx, miner, 1, 0, nil)
|
||||
|
||||
sl, err := miner.SectorsList(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(sl) != 1 {
|
||||
t.Fatal("expected 1 sector")
|
||||
}
|
||||
|
||||
if sl[0] != CC {
|
||||
t.Fatal("bad")
|
||||
}
|
||||
|
||||
{
|
||||
si, err := client.StateSectorGetInfo(ctx, maddr, CC, types.EmptyTSK)
|
||||
require.NoError(t, err)
|
||||
require.Less(t, 50000, int(si.Expiration))
|
||||
}
|
||||
|
||||
if err := miner.SectorMarkForUpgrade(ctx, sl[0]); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
makeDeal(t, ctx, 6, client, miner, false, false)
|
||||
|
||||
// Validate upgrade
|
||||
|
||||
{
|
||||
exp, err := client.StateSectorExpiration(ctx, maddr, CC, types.EmptyTSK)
|
||||
require.NoError(t, err)
|
||||
require.Greater(t, 50000, int(exp.OnTime))
|
||||
}
|
||||
{
|
||||
exp, err := client.StateSectorExpiration(ctx, maddr, Upgraded, types.EmptyTSK)
|
||||
require.NoError(t, err)
|
||||
require.Less(t, 50000, int(exp.OnTime))
|
||||
}
|
||||
|
||||
fmt.Println("shutting down mining")
|
||||
atomic.AddInt64(&mine, -1)
|
||||
<-done
|
||||
}
|
||||
+220
-22
@@ -12,15 +12,19 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
files "github.com/ipfs/go-ipfs-files"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"github.com/ipld/go-car"
|
||||
|
||||
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
sealing "github.com/filecoin-project/lotus/extern/storage-sealing"
|
||||
"github.com/filecoin-project/lotus/miner"
|
||||
dag "github.com/ipfs/go-merkledag"
|
||||
dstest "github.com/ipfs/go-merkledag/test"
|
||||
unixfile "github.com/ipfs/go-unixfs/file"
|
||||
@@ -30,16 +34,21 @@ import (
|
||||
ipld "github.com/ipfs/go-ipld-format"
|
||||
)
|
||||
|
||||
var MineNext = miner.MineReq{
|
||||
InjectNulls: 0,
|
||||
Done: func(bool, abi.ChainEpoch, error) {},
|
||||
}
|
||||
|
||||
func init() {
|
||||
logging.SetAllLoggers(logging.LevelInfo)
|
||||
build.InsecurePoStValidation = true
|
||||
}
|
||||
|
||||
func TestDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration, carExport bool) {
|
||||
func TestDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration, carExport, fastRet bool) {
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, oneMiner)
|
||||
n, sn := b(t, 1, OneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
@@ -59,13 +68,13 @@ func TestDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration, carExport
|
||||
defer close(done)
|
||||
for atomic.LoadInt64(&mine) == 1 {
|
||||
time.Sleep(blocktime)
|
||||
if err := sn[0].MineOne(ctx, func(bool, error) {}); err != nil {
|
||||
if err := sn[0].MineOne(ctx, MineNext); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
makeDeal(t, ctx, 6, client, miner, carExport)
|
||||
makeDeal(t, ctx, 6, client, miner, carExport, fastRet)
|
||||
|
||||
atomic.AddInt64(&mine, -1)
|
||||
fmt.Println("shutting down mining")
|
||||
@@ -76,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, 1, OneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
@@ -97,21 +106,21 @@ func TestDoubleDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
defer close(done)
|
||||
for atomic.LoadInt64(&mine) == 1 {
|
||||
time.Sleep(blocktime)
|
||||
if err := sn[0].MineOne(ctx, func(bool, error) {}); err != nil {
|
||||
if err := sn[0].MineOne(ctx, MineNext); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
makeDeal(t, ctx, 6, client, miner, false)
|
||||
makeDeal(t, ctx, 7, client, miner, false)
|
||||
makeDeal(t, ctx, 6, client, miner, false, false)
|
||||
makeDeal(t, ctx, 7, client, miner, false, false)
|
||||
|
||||
atomic.AddInt64(&mine, -1)
|
||||
fmt.Println("shutting down mining")
|
||||
<-done
|
||||
}
|
||||
|
||||
func makeDeal(t *testing.T, ctx context.Context, rseed int, client *impl.FullNodeAPI, miner TestStorageNode, carExport bool) {
|
||||
func makeDeal(t *testing.T, ctx context.Context, rseed int, client *impl.FullNodeAPI, miner TestStorageNode, carExport, fastRet bool) {
|
||||
data := make([]byte, 1600)
|
||||
rand.New(rand.NewSource(int64(rseed))).Read(data)
|
||||
|
||||
@@ -123,18 +132,151 @@ func makeDeal(t *testing.T, ctx context.Context, rseed int, client *impl.FullNod
|
||||
|
||||
fmt.Println("FILE CID: ", fcid)
|
||||
|
||||
deal := startDeal(t, ctx, miner, client, fcid)
|
||||
deal := startDeal(t, ctx, miner, client, fcid, fastRet)
|
||||
|
||||
// TODO: this sleep is only necessary because deals don't immediately get logged in the dealstore, we should fix this
|
||||
time.Sleep(time.Second)
|
||||
waitDealSealed(t, ctx, client, deal)
|
||||
waitDealSealed(t, ctx, miner, client, deal, false)
|
||||
|
||||
// Retrieval
|
||||
info, err := client.ClientGetDealInfo(ctx, *deal)
|
||||
require.NoError(t, err)
|
||||
|
||||
testRetrieval(t, ctx, err, client, fcid, carExport, data)
|
||||
testRetrieval(t, ctx, client, fcid, &info.PieceCID, carExport, data)
|
||||
}
|
||||
|
||||
func startDeal(t *testing.T, ctx context.Context, miner TestStorageNode, client *impl.FullNodeAPI, fcid cid.Cid) *cid.Cid {
|
||||
func TestFastRetrievalDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, 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)
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
|
||||
mine := int64(1)
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer close(done)
|
||||
for atomic.LoadInt64(&mine) == 1 {
|
||||
time.Sleep(blocktime)
|
||||
if err := sn[0].MineOne(ctx, MineNext); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
data := make([]byte, 1600)
|
||||
rand.New(rand.NewSource(int64(8))).Read(data)
|
||||
|
||||
r := bytes.NewReader(data)
|
||||
fcid, err := client.ClientImportLocal(ctx, r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println("FILE CID: ", fcid)
|
||||
|
||||
deal := startDeal(t, ctx, miner, client, fcid, true)
|
||||
|
||||
waitDealPublished(t, ctx, miner, deal)
|
||||
fmt.Println("deal published, retrieving")
|
||||
// Retrieval
|
||||
info, err := client.ClientGetDealInfo(ctx, *deal)
|
||||
require.NoError(t, err)
|
||||
|
||||
testRetrieval(t, ctx, client, fcid, &info.PieceCID, false, data)
|
||||
atomic.AddInt64(&mine, -1)
|
||||
fmt.Println("shutting down mining")
|
||||
<-done
|
||||
}
|
||||
|
||||
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)
|
||||
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)
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
|
||||
mine := int64(1)
|
||||
done := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
defer close(done)
|
||||
for atomic.LoadInt64(&mine) == 1 {
|
||||
time.Sleep(blocktime)
|
||||
if err := sn[0].MineOne(ctx, MineNext); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
{
|
||||
data1 := make([]byte, 800)
|
||||
rand.New(rand.NewSource(int64(3))).Read(data1)
|
||||
r := bytes.NewReader(data1)
|
||||
|
||||
fcid1, err := client.ClientImportLocal(ctx, r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
data2 := make([]byte, 800)
|
||||
rand.New(rand.NewSource(int64(9))).Read(data2)
|
||||
r2 := bytes.NewReader(data2)
|
||||
|
||||
fcid2, err := client.ClientImportLocal(ctx, r2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
deal1 := startDeal(t, ctx, miner, client, fcid1, true)
|
||||
|
||||
// TODO: this sleep is only necessary because deals don't immediately get logged in the dealstore, we should fix this
|
||||
time.Sleep(time.Second)
|
||||
waitDealSealed(t, ctx, miner, client, deal1, true)
|
||||
|
||||
deal2 := startDeal(t, ctx, miner, client, fcid2, true)
|
||||
|
||||
time.Sleep(time.Second)
|
||||
waitDealSealed(t, ctx, miner, client, deal2, false)
|
||||
|
||||
// Retrieval
|
||||
info, err := client.ClientGetDealInfo(ctx, *deal2)
|
||||
require.NoError(t, err)
|
||||
|
||||
rf, _ := miner.SectorsRefs(ctx)
|
||||
fmt.Printf("refs: %+v\n", rf)
|
||||
|
||||
testRetrieval(t, ctx, client, fcid2, &info.PieceCID, false, data2)
|
||||
}
|
||||
|
||||
atomic.AddInt64(&mine, -1)
|
||||
fmt.Println("shutting down mining")
|
||||
<-done
|
||||
}
|
||||
|
||||
func startDeal(t *testing.T, ctx context.Context, miner TestStorageNode, client *impl.FullNodeAPI, fcid cid.Cid, fastRet bool) *cid.Cid {
|
||||
maddr, err := miner.ActorAddress(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -145,11 +287,15 @@ func startDeal(t *testing.T, ctx context.Context, miner TestStorageNode, client
|
||||
t.Fatal(err)
|
||||
}
|
||||
deal, err := client.ClientStartDeal(ctx, &api.StartDealParams{
|
||||
Data: &storagemarket.DataRef{Root: fcid},
|
||||
Data: &storagemarket.DataRef{
|
||||
TransferType: storagemarket.TTGraphsync,
|
||||
Root: fcid,
|
||||
},
|
||||
Wallet: addr,
|
||||
Miner: maddr,
|
||||
EpochPrice: types.NewInt(1000000),
|
||||
MinBlocksDuration: 100,
|
||||
MinBlocksDuration: uint64(build.MinDealDuration),
|
||||
FastRetrieval: fastRet,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("%+v", err)
|
||||
@@ -157,7 +303,7 @@ func startDeal(t *testing.T, ctx context.Context, miner TestStorageNode, client
|
||||
return deal
|
||||
}
|
||||
|
||||
func waitDealSealed(t *testing.T, ctx context.Context, client *impl.FullNodeAPI, deal *cid.Cid) {
|
||||
func waitDealSealed(t *testing.T, ctx context.Context, miner TestStorageNode, client *impl.FullNodeAPI, deal *cid.Cid, noseal bool) {
|
||||
loop:
|
||||
for {
|
||||
di, err := client.ClientGetDealInfo(ctx, *deal)
|
||||
@@ -165,6 +311,11 @@ loop:
|
||||
t.Fatal(err)
|
||||
}
|
||||
switch di.State {
|
||||
case storagemarket.StorageDealSealing:
|
||||
if noseal {
|
||||
return
|
||||
}
|
||||
startSealingWaiting(t, ctx, miner)
|
||||
case storagemarket.StorageDealProposalRejected:
|
||||
t.Fatal("deal rejected")
|
||||
case storagemarket.StorageDealFailing:
|
||||
@@ -180,8 +331,53 @@ loop:
|
||||
}
|
||||
}
|
||||
|
||||
func testRetrieval(t *testing.T, ctx context.Context, err error, client *impl.FullNodeAPI, fcid cid.Cid, carExport bool, data []byte) {
|
||||
offers, err := client.ClientFindData(ctx, fcid)
|
||||
func waitDealPublished(t *testing.T, ctx context.Context, miner TestStorageNode, deal *cid.Cid) {
|
||||
subCtx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
updates, err := miner.MarketGetDealUpdates(subCtx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
t.Fatal("context timeout")
|
||||
case di := <-updates:
|
||||
if deal.Equals(di.ProposalCid) {
|
||||
switch di.State {
|
||||
case storagemarket.StorageDealProposalRejected:
|
||||
t.Fatal("deal rejected")
|
||||
case storagemarket.StorageDealFailing:
|
||||
t.Fatal("deal failed")
|
||||
case storagemarket.StorageDealError:
|
||||
t.Fatal("deal errored", di.Message)
|
||||
case storagemarket.StorageDealFinalizing, storagemarket.StorageDealSealing, storagemarket.StorageDealActive:
|
||||
fmt.Println("COMPLETE", di)
|
||||
return
|
||||
}
|
||||
fmt.Println("Deal state: ", storagemarket.DealStates[di.State])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func startSealingWaiting(t *testing.T, ctx context.Context, miner TestStorageNode) {
|
||||
snums, err := miner.SectorsList(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
for _, snum := range snums {
|
||||
si, err := miner.SectorsStatus(ctx, snum, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Logf("Sector state: %s", si.State)
|
||||
if si.State == api.SectorState(sealing.WaitDeals) {
|
||||
require.NoError(t, miner.SectorStartSealing(ctx, snum))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testRetrieval(t *testing.T, ctx context.Context, client *impl.FullNodeAPI, fcid cid.Cid, piece *cid.Cid, carExport bool, data []byte) {
|
||||
offers, err := client.ClientFindData(ctx, fcid, piece)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -205,9 +401,11 @@ func testRetrieval(t *testing.T, ctx context.Context, err error, client *impl.Fu
|
||||
Path: filepath.Join(rpath, "ret"),
|
||||
IsCAR: carExport,
|
||||
}
|
||||
err = client.ClientRetrieve(ctx, offers[0].Order(caddr), ref)
|
||||
if err != nil {
|
||||
t.Fatalf("%+v", err)
|
||||
updates, err := client.ClientRetrieveWithEvents(ctx, offers[0].Order(caddr), ref)
|
||||
for update := range updates {
|
||||
if update.Err != "" {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
rdata, err := ioutil.ReadFile(filepath.Join(rpath, "ret"))
|
||||
|
||||
+66
-59
@@ -12,36 +12,39 @@ import (
|
||||
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/miner"
|
||||
"github.com/filecoin-project/lotus/node/impl"
|
||||
)
|
||||
|
||||
//nolint:deadcode,varcheck
|
||||
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, 1, OneMiner)
|
||||
api := apis[0]
|
||||
|
||||
h1, err := api.ChainHead(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, abi.ChainEpoch(0), h1.Height())
|
||||
|
||||
newHeads, err := api.ChainNotify(ctx)
|
||||
require.NoError(t, err)
|
||||
<-newHeads
|
||||
initHead := (<-newHeads)[0]
|
||||
baseHeight := initHead.Val.Height()
|
||||
|
||||
err = sn[0].MineOne(ctx, func(bool, error) {})
|
||||
h1, err := api.ChainHead(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, int64(h1.Height()), int64(baseHeight))
|
||||
|
||||
MineUntilBlock(ctx, t, apis[0], sn[0], nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
<-newHeads
|
||||
|
||||
h2, err := api.ChainHead(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, abi.ChainEpoch(1), h2.Height())
|
||||
require.Greater(t, int64(h2.Height()), int64(h1.Height()))
|
||||
}
|
||||
|
||||
func (ts *testSuite) testMiningReal(t *testing.T) {
|
||||
@@ -51,34 +54,37 @@ func (ts *testSuite) testMiningReal(t *testing.T) {
|
||||
}()
|
||||
|
||||
ctx := context.Background()
|
||||
apis, sn := ts.makeNodes(t, 1, oneMiner)
|
||||
apis, sn := ts.makeNodes(t, 1, OneMiner)
|
||||
api := apis[0]
|
||||
|
||||
h1, err := api.ChainHead(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, abi.ChainEpoch(0), h1.Height())
|
||||
|
||||
newHeads, err := api.ChainNotify(ctx)
|
||||
require.NoError(t, err)
|
||||
<-newHeads
|
||||
initHead := (<-newHeads)[0]
|
||||
if initHead.Val.Height() != 2 {
|
||||
<-newHeads
|
||||
}
|
||||
|
||||
err = sn[0].MineOne(ctx, func(bool, error) {})
|
||||
h1, err := api.ChainHead(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, abi.ChainEpoch(2), h1.Height())
|
||||
|
||||
MineUntilBlock(ctx, t, apis[0], sn[0], nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
<-newHeads
|
||||
|
||||
h2, err := api.ChainHead(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, abi.ChainEpoch(1), h2.Height())
|
||||
require.Equal(t, abi.ChainEpoch(3), h2.Height())
|
||||
|
||||
err = sn[0].MineOne(ctx, func(bool, error) {})
|
||||
MineUntilBlock(ctx, t, apis[0], sn[0], nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
<-newHeads
|
||||
|
||||
h2, err = api.ChainHead(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, abi.ChainEpoch(2), h2.Height())
|
||||
require.Equal(t, abi.ChainEpoch(4), h2.Height())
|
||||
}
|
||||
|
||||
func TestDealMining(t *testing.T, b APIBuilder, blocktime time.Duration, carExport bool) {
|
||||
@@ -89,7 +95,7 @@ func TestDealMining(t *testing.T, b APIBuilder, blocktime time.Duration, carExpo
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, []StorageMiner{
|
||||
{Full: 0, Preseal: PresealGenesis},
|
||||
{Full: 0, Preseal: 0}, // TODO: Add support for storage miners on non-first full node
|
||||
{Full: 0, Preseal: 0}, // TODO: Add support for miners on non-first full node
|
||||
})
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
provider := sn[1]
|
||||
@@ -125,28 +131,30 @@ func TestDealMining(t *testing.T, b APIBuilder, blocktime time.Duration, carExpo
|
||||
done := make(chan struct{})
|
||||
minedTwo := make(chan struct{})
|
||||
|
||||
m2addr, err := sn[1].ActorAddress(context.TODO())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
doneMinedTwo := false
|
||||
defer close(done)
|
||||
|
||||
prevExpect := 0
|
||||
complChan := minedTwo
|
||||
for atomic.LoadInt32(&mine) != 0 {
|
||||
wait := make(chan int, 2)
|
||||
mdone := func(mined bool, err error) {
|
||||
go func() {
|
||||
n := 0
|
||||
if mined {
|
||||
n = 1
|
||||
}
|
||||
wait <- n
|
||||
}()
|
||||
wait := make(chan int)
|
||||
mdone := func(mined bool, _ abi.ChainEpoch, err error) {
|
||||
n := 0
|
||||
if mined {
|
||||
n = 1
|
||||
}
|
||||
wait <- n
|
||||
}
|
||||
|
||||
if err := sn[0].MineOne(ctx, mdone); err != nil {
|
||||
if err := sn[0].MineOne(ctx, miner.MineReq{Done: mdone}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if err := sn[1].MineOne(ctx, mdone); err != nil {
|
||||
if err := sn[1].MineOne(ctx, miner.MineReq{Done: mdone}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -154,43 +162,42 @@ func TestDealMining(t *testing.T, b APIBuilder, blocktime time.Duration, carExpo
|
||||
expect += <-wait
|
||||
|
||||
time.Sleep(blocktime)
|
||||
|
||||
for {
|
||||
n := 0
|
||||
for i, node := range sn {
|
||||
mb, err := node.MiningBase(ctx)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(mb.Cids()) != expect {
|
||||
log.Warnf("node %d mining base not complete (%d, want %d)", i, len(mb.Cids()), expect)
|
||||
continue
|
||||
}
|
||||
n++
|
||||
}
|
||||
if n == len(sn) {
|
||||
break
|
||||
}
|
||||
time.Sleep(blocktime)
|
||||
if expect == 0 {
|
||||
// null block
|
||||
continue
|
||||
}
|
||||
|
||||
if prevExpect == 2 && expect == 2 && !doneMinedTwo {
|
||||
close(minedTwo)
|
||||
doneMinedTwo = true
|
||||
var nodeOneMined bool
|
||||
for _, node := range sn {
|
||||
mb, err := node.MiningBase(ctx)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, b := range mb.Blocks() {
|
||||
if b.Miner == m2addr {
|
||||
nodeOneMined = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if nodeOneMined && complChan != nil {
|
||||
close(complChan)
|
||||
complChan = nil
|
||||
}
|
||||
|
||||
prevExpect = expect
|
||||
}
|
||||
}()
|
||||
|
||||
deal := startDeal(t, ctx, provider, client, fcid)
|
||||
deal := startDeal(t, ctx, provider, client, fcid, false)
|
||||
|
||||
// TODO: this sleep is only necessary because deals don't immediately get logged in the dealstore, we should fix this
|
||||
time.Sleep(time.Second)
|
||||
|
||||
waitDealSealed(t, ctx, client, deal)
|
||||
waitDealSealed(t, ctx, provider, client, deal, false)
|
||||
|
||||
<-minedTwo
|
||||
|
||||
|
||||
@@ -0,0 +1,259 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"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)
|
||||
|
||||
paymentCreator := n[0]
|
||||
paymentReceiver := n[1]
|
||||
miner := sn[0]
|
||||
|
||||
// get everyone connected
|
||||
addrs, err := paymentCreator.NetAddrsListen(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := paymentReceiver.NetConnect(ctx, addrs); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := miner.NetConnect(ctx, addrs); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// start mining blocks
|
||||
bm := NewBlockMiner(ctx, t, miner, blocktime)
|
||||
bm.MineBlocks()
|
||||
|
||||
// send some funds to register the receiver
|
||||
receiverAddr, err := paymentReceiver.WalletNew(ctx, wallet.ActSigType("secp256k1"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
SendFunds(ctx, t, paymentCreator, receiverAddr, abi.NewTokenAmount(1e18))
|
||||
|
||||
// setup the payment channel
|
||||
createrAddr, err := paymentCreator.WalletDefaultAddress(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
channelAmt := int64(100000)
|
||||
channelInfo, err := paymentCreator.PaychGet(ctx, createrAddr, receiverAddr, abi.NewTokenAmount(channelAmt))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
channel, err := paymentCreator.PaychGetWaitReady(ctx, channelInfo.WaitSentinel)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// allocate three lanes
|
||||
var lanes []uint64
|
||||
for i := 0; i < 3; i++ {
|
||||
lane, err := paymentCreator.PaychAllocateLane(ctx, channel)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
lanes = append(lanes, lane)
|
||||
}
|
||||
|
||||
// Make two vouchers each for each lane, then save on the other side
|
||||
// Note that the voucher with a value of 2000 has a higher nonce, so it
|
||||
// supersedes the voucher with a value of 1000
|
||||
for _, lane := range lanes {
|
||||
vouch1, err := paymentCreator.PaychVoucherCreate(ctx, channel, abi.NewTokenAmount(1000), lane)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if vouch1.Voucher == nil {
|
||||
t.Fatal(fmt.Errorf("Not enough funds to create voucher: missing %d", vouch1.Shortfall))
|
||||
}
|
||||
vouch2, err := paymentCreator.PaychVoucherCreate(ctx, channel, abi.NewTokenAmount(2000), lane)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if vouch2.Voucher == nil {
|
||||
t.Fatal(fmt.Errorf("Not enough funds to create voucher: missing %d", vouch2.Shortfall))
|
||||
}
|
||||
delta1, err := paymentReceiver.PaychVoucherAdd(ctx, channel, vouch1.Voucher, nil, abi.NewTokenAmount(1000))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !delta1.Equals(abi.NewTokenAmount(1000)) {
|
||||
t.Fatal("voucher didn't have the right amount")
|
||||
}
|
||||
delta2, err := paymentReceiver.PaychVoucherAdd(ctx, channel, vouch2.Voucher, nil, abi.NewTokenAmount(1000))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !delta2.Equals(abi.NewTokenAmount(1000)) {
|
||||
t.Fatal("voucher didn't have the right amount")
|
||||
}
|
||||
}
|
||||
|
||||
// settle the payment channel
|
||||
settleMsgCid, err := paymentCreator.PaychSettle(ctx, channel)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
res := waitForMessage(ctx, t, paymentCreator, settleMsgCid, time.Second*10, "settle")
|
||||
if res.Receipt.ExitCode != 0 {
|
||||
t.Fatal("Unable to settle payment channel")
|
||||
}
|
||||
|
||||
// wait for the receiver to submit their vouchers
|
||||
ev := events.NewEvents(ctx, paymentCreator)
|
||||
preds := state.NewStatePredicates(paymentCreator)
|
||||
finished := make(chan struct{})
|
||||
err = ev.StateChanged(func(ts *types.TipSet) (done bool, more bool, err error) {
|
||||
act, err := paymentCreator.StateReadState(ctx, channel, ts.Key())
|
||||
if err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
state := act.State.(paych.State)
|
||||
if state.ToSend.GreaterThanEqual(abi.NewTokenAmount(6000)) {
|
||||
return true, false, nil
|
||||
}
|
||||
return false, true, nil
|
||||
}, func(oldTs, newTs *types.TipSet, states events.StateChange, curH abi.ChainEpoch) (more bool, err error) {
|
||||
toSendChange := states.(*state.PayChToSendChange)
|
||||
if toSendChange.NewToSend.GreaterThanEqual(abi.NewTokenAmount(6000)) {
|
||||
close(finished)
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
}, func(ctx context.Context, ts *types.TipSet) error {
|
||||
return nil
|
||||
}, int(build.MessageConfidence)+1, build.SealRandomnessLookbackLimit, func(oldTs, newTs *types.TipSet) (bool, events.StateChange, error) {
|
||||
return preds.OnPaymentChannelActorChanged(channel, preds.OnToSendAmountChanges())(ctx, oldTs.Key(), newTs.Key())
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-finished:
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("Timed out waiting for receiver to submit vouchers")
|
||||
}
|
||||
|
||||
// wait for the settlement period to pass before collecting
|
||||
waitForBlocks(ctx, t, bm, paymentReceiver, receiverAddr, paych.SettleDelay)
|
||||
|
||||
creatorPreCollectBalance, err := paymentCreator.WalletBalance(ctx, createrAddr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// collect funds (from receiver, though either party can do it)
|
||||
collectMsg, err := paymentReceiver.PaychCollect(ctx, channel)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
res, err = paymentReceiver.StateWaitMsg(ctx, collectMsg, 3)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if res.Receipt.ExitCode != 0 {
|
||||
t.Fatal("unable to collect on payment channel")
|
||||
}
|
||||
|
||||
// Finally, check the balance for the creator
|
||||
currentCreatorBalance, err := paymentCreator.WalletBalance(ctx, createrAddr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// The highest nonce voucher that the creator sent on each lane is 2000
|
||||
totalVouchers := int64(len(lanes) * 2000)
|
||||
|
||||
// When receiver submits the tokens to the chain, creator should get a
|
||||
// refund on the remaining balance, which is
|
||||
// channel amount - total voucher value
|
||||
expectedRefund := channelAmt - totalVouchers
|
||||
delta := big.Sub(currentCreatorBalance, creatorPreCollectBalance)
|
||||
if !delta.Equals(abi.NewTokenAmount(expectedRefund)) {
|
||||
t.Fatalf("did not send correct funds from creator: expected %d, got %d", expectedRefund, delta)
|
||||
}
|
||||
|
||||
// shut down mining
|
||||
bm.Stop()
|
||||
}
|
||||
|
||||
func waitForBlocks(ctx context.Context, t *testing.T, bm *BlockMiner, paymentReceiver TestNode, receiverAddr address.Address, count int) {
|
||||
// We need to add null blocks in batches, if we add too many the chain can't sync
|
||||
batchSize := 60
|
||||
for i := 0; i < count; i += batchSize {
|
||||
size := batchSize
|
||||
if i > count {
|
||||
size = count - i
|
||||
}
|
||||
|
||||
// Add a batch of null blocks
|
||||
atomic.StoreInt64(&bm.nulls, int64(size-1))
|
||||
|
||||
// Add a real block
|
||||
m, err := paymentReceiver.MpoolPushMessage(ctx, &types.Message{
|
||||
To: builtin.BurntFundsActorAddr,
|
||||
From: receiverAddr,
|
||||
Value: types.NewInt(0),
|
||||
}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = paymentReceiver.StateWaitMsg(ctx, m.Cid(), 1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func waitForMessage(ctx context.Context, t *testing.T, paymentCreator TestNode, msgCid cid.Cid, duration time.Duration, desc string) *api.MsgLookup {
|
||||
ctx, cancel := context.WithTimeout(ctx, duration)
|
||||
defer cancel()
|
||||
|
||||
fmt.Println("Waiting for", desc)
|
||||
res, err := paymentCreator.StateWaitMsg(ctx, msgCid, 1)
|
||||
if err != nil {
|
||||
fmt.Println("Error waiting for", desc, err)
|
||||
t.Fatal(err)
|
||||
}
|
||||
if res.Receipt.ExitCode != 0 {
|
||||
t.Fatalf("did not successfully send %s", desc)
|
||||
}
|
||||
fmt.Println("Confirmed", desc)
|
||||
return res
|
||||
}
|
||||
+16
-5
@@ -4,21 +4,30 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/miner"
|
||||
)
|
||||
|
||||
type TestNode struct {
|
||||
api.FullNode
|
||||
// ListenAddr is the address on which an API server is listening, if an
|
||||
// API server is created for this Node
|
||||
ListenAddr multiaddr.Multiaddr
|
||||
}
|
||||
|
||||
type TestStorageNode struct {
|
||||
api.StorageMiner
|
||||
// ListenAddr is the address on which an API server is listening, if an
|
||||
// API server is created for this Node
|
||||
ListenAddr multiaddr.Multiaddr
|
||||
|
||||
MineOne func(context.Context, func(bool, error)) error
|
||||
MineOne func(context.Context, miner.MineReq) error
|
||||
}
|
||||
|
||||
var PresealGenesis = -1
|
||||
@@ -53,11 +62,13 @@ func TestApis(t *testing.T, b APIBuilder) {
|
||||
t.Run("testMiningReal", ts.testMiningReal)
|
||||
}
|
||||
|
||||
var oneMiner = []StorageMiner{{Full: 0, Preseal: PresealGenesis}}
|
||||
var OneMiner = []StorageMiner{{Full: 0, Preseal: PresealGenesis}}
|
||||
|
||||
func (ts *testSuite) testVersion(t *testing.T) {
|
||||
build.RunningNodeType = build.NodeFull
|
||||
|
||||
ctx := context.Background()
|
||||
apis, _ := ts.makeNodes(t, 1, oneMiner)
|
||||
apis, _ := ts.makeNodes(t, 1, OneMiner)
|
||||
api := apis[0]
|
||||
|
||||
v, err := api.Version(ctx)
|
||||
@@ -69,7 +80,7 @@ func (ts *testSuite) testVersion(t *testing.T) {
|
||||
|
||||
func (ts *testSuite) testID(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
apis, _ := ts.makeNodes(t, 1, oneMiner)
|
||||
apis, _ := ts.makeNodes(t, 1, OneMiner)
|
||||
api := apis[0]
|
||||
|
||||
id, err := api.ID(ctx)
|
||||
@@ -81,7 +92,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, 2, OneMiner)
|
||||
|
||||
p, err := apis[0].NetPeers(ctx)
|
||||
if err != nil {
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/miner"
|
||||
)
|
||||
|
||||
func SendFunds(ctx context.Context, t *testing.T, sender TestNode, addr address.Address, amount abi.TokenAmount) {
|
||||
senderAddr, err := sender.WalletDefaultAddress(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
msg := &types.Message{
|
||||
From: senderAddr,
|
||||
To: addr,
|
||||
Value: amount,
|
||||
}
|
||||
|
||||
sm, err := sender.MpoolPushMessage(ctx, msg, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
res, err := sender.StateWaitMsg(ctx, sm.Cid(), 1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if res.Receipt.ExitCode != 0 {
|
||||
t.Fatal("did not successfully send money")
|
||||
}
|
||||
}
|
||||
|
||||
func MineUntilBlock(ctx context.Context, t *testing.T, fn TestNode, sn TestStorageNode, cb func(abi.ChainEpoch)) {
|
||||
for i := 0; i < 1000; i++ {
|
||||
var success bool
|
||||
var err error
|
||||
var epoch abi.ChainEpoch
|
||||
wait := make(chan struct{})
|
||||
mineErr := sn.MineOne(ctx, miner.MineReq{
|
||||
Done: func(win bool, ep abi.ChainEpoch, e error) {
|
||||
success = win
|
||||
err = e
|
||||
epoch = ep
|
||||
wait <- struct{}{}
|
||||
},
|
||||
})
|
||||
if mineErr != nil {
|
||||
t.Fatal(mineErr)
|
||||
}
|
||||
<-wait
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if success {
|
||||
// Wait until it shows up on the given full nodes ChainHead
|
||||
nloops := 50
|
||||
for i := 0; i < nloops; i++ {
|
||||
ts, err := fn.ChainHead(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if ts.Height() == epoch {
|
||||
break
|
||||
}
|
||||
if i == nloops-1 {
|
||||
t.Fatal("block never managed to sync to node")
|
||||
}
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
}
|
||||
|
||||
if cb != nil {
|
||||
cb(epoch)
|
||||
}
|
||||
return
|
||||
}
|
||||
t.Log("did not mine block, trying again", i)
|
||||
}
|
||||
t.Fatal("failed to mine 1000 times in a row...")
|
||||
}
|
||||
+177
-25
@@ -3,7 +3,7 @@ package test
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -11,19 +11,29 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/mock"
|
||||
sealing "github.com/filecoin-project/lotus/extern/storage-sealing"
|
||||
miner2 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
sealing "github.com/filecoin-project/storage-fsm"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
bminer "github.com/filecoin-project/lotus/miner"
|
||||
"github.com/filecoin-project/lotus/node/impl"
|
||||
)
|
||||
|
||||
func TestPledgeSector(t *testing.T, b APIBuilder, blocktime time.Duration, nSectors int) {
|
||||
os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
func init() {
|
||||
err := os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("failed to set BELLMAN_NO_GPU env variable: %s", err))
|
||||
}
|
||||
}
|
||||
|
||||
func TestPledgeSector(t *testing.T, b APIBuilder, blocktime time.Duration, nSectors int) {
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, oneMiner)
|
||||
n, sn := b(t, 1, OneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
@@ -35,41 +45,46 @@ func TestPledgeSector(t *testing.T, b APIBuilder, blocktime time.Duration, nSect
|
||||
if err := miner.NetConnect(ctx, addrinfo); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
build.Clock.Sleep(time.Second)
|
||||
|
||||
mine := true
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer close(done)
|
||||
for mine {
|
||||
time.Sleep(blocktime)
|
||||
if err := sn[0].MineOne(ctx, func(bool, error) {}); err != nil {
|
||||
build.Clock.Sleep(blocktime)
|
||||
if err := sn[0].MineOne(ctx, bminer.MineReq{Done: func(bool, abi.ChainEpoch, error) {
|
||||
|
||||
}}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
pledgeSectors(t, ctx, miner, nSectors)
|
||||
pledgeSectors(t, ctx, miner, nSectors, 0, nil)
|
||||
|
||||
mine = false
|
||||
<-done
|
||||
}
|
||||
|
||||
func pledgeSectors(t *testing.T, ctx context.Context, miner TestStorageNode, n int) {
|
||||
func pledgeSectors(t *testing.T, ctx context.Context, miner TestStorageNode, n, existing int, blockNotif <-chan struct{}) {
|
||||
for i := 0; i < n; i++ {
|
||||
err := miner.PledgeSector(ctx)
|
||||
require.NoError(t, err)
|
||||
if i%3 == 0 && blockNotif != nil {
|
||||
<-blockNotif
|
||||
}
|
||||
}
|
||||
|
||||
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) >= n {
|
||||
if len(s) >= n+existing {
|
||||
break
|
||||
}
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
build.Clock.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
fmt.Printf("All sectors is fsm\n")
|
||||
@@ -84,7 +99,7 @@ func pledgeSectors(t *testing.T, ctx context.Context, miner TestStorageNode, n i
|
||||
|
||||
for len(toCheck) > 0 {
|
||||
for n := range toCheck {
|
||||
st, err := miner.SectorsStatus(ctx, n)
|
||||
st, err := miner.SectorsStatus(ctx, n, false)
|
||||
require.NoError(t, err)
|
||||
if st.State == api.SectorState(sealing.Proving) {
|
||||
delete(toCheck, n)
|
||||
@@ -94,16 +109,14 @@ func pledgeSectors(t *testing.T, ctx context.Context, miner TestStorageNode, n i
|
||||
}
|
||||
}
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
build.Clock.Sleep(100 * time.Millisecond)
|
||||
fmt.Printf("WaitSeal: %d\n", len(s))
|
||||
}
|
||||
}
|
||||
|
||||
func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSectors int) {
|
||||
os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, oneMiner)
|
||||
n, sn := b(t, 1, OneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
@@ -115,21 +128,21 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector
|
||||
if err := miner.NetConnect(ctx, addrinfo); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
build.Clock.Sleep(time.Second)
|
||||
|
||||
mine := true
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer close(done)
|
||||
for mine {
|
||||
time.Sleep(blocktime)
|
||||
if err := sn[0].MineOne(ctx, func(bool, error) {}); err != nil {
|
||||
build.Clock.Sleep(blocktime)
|
||||
if err := sn[0].MineOne(ctx, MineNext); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
pledgeSectors(t, ctx, miner, nSectors)
|
||||
pledgeSectors(t, ctx, miner, nSectors, 0, nil)
|
||||
|
||||
maddr, err := miner.ActorAddress(ctx)
|
||||
require.NoError(t, err)
|
||||
@@ -137,7 +150,10 @@ 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("Running one proving periods\n")
|
||||
mid, err := address.IDFromAddress(maddr)
|
||||
require.NoError(t, err)
|
||||
|
||||
fmt.Printf("Running one proving period\n")
|
||||
|
||||
for {
|
||||
head, err := client.ChainHead(ctx)
|
||||
@@ -150,7 +166,7 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector
|
||||
if head.Height()%100 == 0 {
|
||||
fmt.Printf("@%d\n", head.Height())
|
||||
}
|
||||
time.Sleep(blocktime)
|
||||
build.Clock.Sleep(blocktime)
|
||||
}
|
||||
|
||||
p, err := client.StateMinerPower(ctx, maddr, types.EmptyTSK)
|
||||
@@ -162,7 +178,143 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector
|
||||
require.Equal(t, p.MinerPower, p.TotalPower)
|
||||
require.Equal(t, p.MinerPower.RawBytePower, types.NewInt(uint64(ssz)*uint64(nSectors+GenesisPreseals)))
|
||||
|
||||
// TODO: Inject faults here
|
||||
fmt.Printf("Drop some sectors\n")
|
||||
|
||||
// Drop 2 sectors from deadline 2 partition 0 (full partition / deadline)
|
||||
{
|
||||
parts, err := client.StateMinerPartitions(ctx, maddr, 2, types.EmptyTSK)
|
||||
require.NoError(t, err)
|
||||
require.Greater(t, len(parts), 0)
|
||||
|
||||
n, err := parts[0].Sectors.Count()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint64(2), n)
|
||||
|
||||
// Drop the partition
|
||||
err = parts[0].Sectors.ForEach(func(sid uint64) error {
|
||||
return miner.StorageMiner.(*impl.StorageMinerAPI).IStorageMgr.(*mock.SectorMgr).MarkFailed(abi.SectorID{
|
||||
Miner: abi.ActorID(mid),
|
||||
Number: abi.SectorNumber(sid),
|
||||
}, true)
|
||||
})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
var s abi.SectorID
|
||||
|
||||
// Drop 1 sectors from deadline 3 partition 0
|
||||
{
|
||||
parts, err := client.StateMinerPartitions(ctx, maddr, 3, types.EmptyTSK)
|
||||
require.NoError(t, err)
|
||||
require.Greater(t, len(parts), 0)
|
||||
|
||||
n, err := parts[0].Sectors.Count()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint64(2), n)
|
||||
|
||||
// Drop the sector
|
||||
sn, err := parts[0].Sectors.First()
|
||||
require.NoError(t, err)
|
||||
|
||||
all, err := parts[0].Sectors.All(2)
|
||||
require.NoError(t, err)
|
||||
fmt.Println("the sectors", all)
|
||||
|
||||
s = abi.SectorID{
|
||||
Miner: abi.ActorID(mid),
|
||||
Number: abi.SectorNumber(sn),
|
||||
}
|
||||
|
||||
err = miner.StorageMiner.(*impl.StorageMinerAPI).IStorageMgr.(*mock.SectorMgr).MarkFailed(s, true)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
di, err = client.StateMinerProvingDeadline(ctx, maddr, types.EmptyTSK)
|
||||
require.NoError(t, err)
|
||||
|
||||
fmt.Printf("Go through another PP, wait for sectors to become faulty\n")
|
||||
|
||||
for {
|
||||
head, err := client.ChainHead(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
if head.Height() > di.PeriodStart+(miner2.WPoStProvingPeriod)+2 {
|
||||
break
|
||||
}
|
||||
|
||||
if head.Height()%100 == 0 {
|
||||
fmt.Printf("@%d\n", head.Height())
|
||||
}
|
||||
build.Clock.Sleep(blocktime)
|
||||
}
|
||||
|
||||
p, err = client.StateMinerPower(ctx, maddr, types.EmptyTSK)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, p.MinerPower, p.TotalPower)
|
||||
|
||||
sectors := p.MinerPower.RawBytePower.Uint64() / uint64(ssz)
|
||||
require.Equal(t, nSectors+GenesisPreseals-3, int(sectors)) // -3 just removed sectors
|
||||
|
||||
fmt.Printf("Recover one sector\n")
|
||||
|
||||
err = miner.StorageMiner.(*impl.StorageMinerAPI).IStorageMgr.(*mock.SectorMgr).MarkFailed(s, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
di, err = client.StateMinerProvingDeadline(ctx, maddr, types.EmptyTSK)
|
||||
require.NoError(t, err)
|
||||
|
||||
for {
|
||||
head, err := client.ChainHead(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
if head.Height() > di.PeriodStart+(miner2.WPoStProvingPeriod)+2 {
|
||||
break
|
||||
}
|
||||
|
||||
if head.Height()%100 == 0 {
|
||||
fmt.Printf("@%d\n", head.Height())
|
||||
}
|
||||
build.Clock.Sleep(blocktime)
|
||||
}
|
||||
|
||||
p, err = client.StateMinerPower(ctx, maddr, types.EmptyTSK)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, p.MinerPower, p.TotalPower)
|
||||
|
||||
sectors = p.MinerPower.RawBytePower.Uint64() / uint64(ssz)
|
||||
require.Equal(t, nSectors+GenesisPreseals-2, int(sectors)) // -2 not recovered sectors
|
||||
|
||||
// pledge a sector after recovery
|
||||
|
||||
pledgeSectors(t, ctx, miner, 1, nSectors, nil)
|
||||
|
||||
{
|
||||
// wait a bit more
|
||||
|
||||
head, err := client.ChainHead(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
waitUntil := head.Height() + 10
|
||||
|
||||
for {
|
||||
head, err := client.ChainHead(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
if head.Height() > waitUntil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p, err = client.StateMinerPower(ctx, maddr, types.EmptyTSK)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, p.MinerPower, p.TotalPower)
|
||||
|
||||
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
|
||||
|
||||
+88
-12
@@ -2,11 +2,17 @@ package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
datatransfer "github.com/filecoin-project/go-data-transfer"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
)
|
||||
|
||||
@@ -40,28 +46,37 @@ type ObjStat struct {
|
||||
|
||||
type PubsubScore struct {
|
||||
ID peer.ID
|
||||
Score float64
|
||||
Score *pubsub.PeerScoreSnapshot
|
||||
}
|
||||
|
||||
type MinerInfo struct {
|
||||
Owner address.Address // Must be an ID-address.
|
||||
Worker address.Address // Must be an ID-address.
|
||||
NewWorker address.Address // Must be an ID-address.
|
||||
Owner address.Address // Must be an ID-address.
|
||||
Worker address.Address // Must be an ID-address.
|
||||
NewWorker address.Address // Must be an ID-address.
|
||||
ControlAddresses []address.Address // Must be an ID-addresses.
|
||||
WorkerChangeEpoch abi.ChainEpoch
|
||||
PeerId peer.ID
|
||||
PeerId *peer.ID
|
||||
Multiaddrs []abi.Multiaddrs
|
||||
SealProofType abi.RegisteredSealProof
|
||||
SectorSize abi.SectorSize
|
||||
WindowPoStPartitionSectors uint64
|
||||
}
|
||||
|
||||
func NewApiMinerInfo(info miner.MinerInfo) MinerInfo {
|
||||
func NewApiMinerInfo(info *miner.MinerInfo) MinerInfo {
|
||||
var pid *peer.ID
|
||||
if peerID, err := peer.IDFromBytes(info.PeerId); err == nil {
|
||||
pid = &peerID
|
||||
}
|
||||
|
||||
mi := MinerInfo{
|
||||
Owner: info.Owner,
|
||||
Worker: info.Worker,
|
||||
NewWorker: address.Undef,
|
||||
WorkerChangeEpoch: -1,
|
||||
PeerId: peer.ID(info.PeerId),
|
||||
Owner: info.Owner,
|
||||
Worker: info.Worker,
|
||||
ControlAddresses: info.ControlAddresses,
|
||||
|
||||
NewWorker: address.Undef,
|
||||
WorkerChangeEpoch: -1,
|
||||
|
||||
PeerId: pid,
|
||||
Multiaddrs: info.Multiaddrs,
|
||||
SealProofType: info.SealProofType,
|
||||
SectorSize: info.SectorSize,
|
||||
@@ -75,3 +90,64 @@ func NewApiMinerInfo(info miner.MinerInfo) MinerInfo {
|
||||
|
||||
return mi
|
||||
}
|
||||
|
||||
type MessageSendSpec struct {
|
||||
MaxFee abi.TokenAmount
|
||||
}
|
||||
|
||||
var DefaultMessageSendSpec = MessageSendSpec{
|
||||
// MaxFee of 0.1FIL
|
||||
MaxFee: abi.NewTokenAmount(int64(build.FilecoinPrecision) / 10),
|
||||
}
|
||||
|
||||
func (ms *MessageSendSpec) Get() MessageSendSpec {
|
||||
if ms == nil {
|
||||
return DefaultMessageSendSpec
|
||||
}
|
||||
|
||||
return *ms
|
||||
}
|
||||
|
||||
type DataTransferChannel struct {
|
||||
TransferID datatransfer.TransferID
|
||||
Status datatransfer.Status
|
||||
BaseCID cid.Cid
|
||||
IsInitiator bool
|
||||
IsSender bool
|
||||
Voucher string
|
||||
Message string
|
||||
OtherPeer peer.ID
|
||||
Transferred uint64
|
||||
}
|
||||
|
||||
// NewDataTransferChannel constructs an API DataTransferChannel type from full channel state snapshot and a host id
|
||||
func NewDataTransferChannel(hostID peer.ID, channelState datatransfer.ChannelState) DataTransferChannel {
|
||||
channel := DataTransferChannel{
|
||||
TransferID: channelState.TransferID(),
|
||||
Status: channelState.Status(),
|
||||
BaseCID: channelState.BaseCID(),
|
||||
IsSender: channelState.Sender() == hostID,
|
||||
Message: channelState.Message(),
|
||||
}
|
||||
stringer, ok := channelState.Voucher().(fmt.Stringer)
|
||||
if ok {
|
||||
channel.Voucher = stringer.String()
|
||||
} else {
|
||||
voucherJSON, err := json.Marshal(channelState.Voucher())
|
||||
if err != nil {
|
||||
channel.Voucher = fmt.Errorf("Voucher Serialization: %w", err).Error()
|
||||
} else {
|
||||
channel.Voucher = string(voucherJSON)
|
||||
}
|
||||
}
|
||||
if channel.IsSender {
|
||||
channel.IsInitiator = !channelState.IsPull()
|
||||
channel.Transferred = channelState.Sent()
|
||||
channel.OtherPeer = channelState.Recipient()
|
||||
} else {
|
||||
channel.IsInitiator = channelState.IsPull()
|
||||
channel.Transferred = channelState.Received()
|
||||
channel.OtherPeer = channelState.Sender()
|
||||
}
|
||||
return channel
|
||||
}
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
)
|
||||
|
||||
type SignFunc = func(context.Context, []byte) (*crypto.Signature, error)
|
||||
|
||||
@@ -38,12 +38,3 @@ func BuiltinBootstrap() ([]peer.AddrInfo, error) {
|
||||
})
|
||||
return out, err
|
||||
}
|
||||
|
||||
func DrandBootstrap() ([]peer.AddrInfo, error) {
|
||||
addrs := []string{
|
||||
"/dnsaddr/pl-eu.testnet.drand.sh/",
|
||||
"/dnsaddr/pl-us.testnet.drand.sh/",
|
||||
"/dnsaddr/pl-sin.testnet.drand.sh/",
|
||||
}
|
||||
return addrutil.ParseAddresses(context.TODO(), addrs)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
/dns4/bootstrap-0-sin.fil-test.net/tcp/1347/p2p/12D3KooWPdUquftaQvoQEtEdsRBAhwD6jopbF2oweVTzR59VbHEd
|
||||
/ip4/86.109.15.57/tcp/1347/p2p/12D3KooWPdUquftaQvoQEtEdsRBAhwD6jopbF2oweVTzR59VbHEd
|
||||
/dns4/bootstrap-0-dfw.fil-test.net/tcp/1347/p2p/12D3KooWQSCkHCzosEyrh8FgYfLejKgEPM5VB6qWzZE3yDAuXn8d
|
||||
/ip4/139.178.84.45/tcp/1347/p2p/12D3KooWQSCkHCzosEyrh8FgYfLejKgEPM5VB6qWzZE3yDAuXn8d
|
||||
/dns4/bootstrap-0-fra.fil-test.net/tcp/1347/p2p/12D3KooWEXN2eQmoyqnNjde9PBAQfQLHN67jcEdWU6JougWrgXJK
|
||||
/ip4/136.144.49.17/tcp/1347/p2p/12D3KooWEXN2eQmoyqnNjde9PBAQfQLHN67jcEdWU6JougWrgXJK
|
||||
/dns4/bootstrap-1-sin.fil-test.net/tcp/1347/p2p/12D3KooWLmJkZd33mJhjg5RrpJ6NFep9SNLXWc4uVngV4TXKwzYw
|
||||
/ip4/86.109.15.123/tcp/1347/p2p/12D3KooWLmJkZd33mJhjg5RrpJ6NFep9SNLXWc4uVngV4TXKwzYw
|
||||
/dns4/bootstrap-1-dfw.fil-test.net/tcp/1347/p2p/12D3KooWGXLHjiz6pTRu7x2pkgTVCoxcCiVxcNLpMnWcJ3JiNEy5
|
||||
/ip4/139.178.86.3/tcp/1347/p2p/12D3KooWGXLHjiz6pTRu7x2pkgTVCoxcCiVxcNLpMnWcJ3JiNEy5
|
||||
/dns4/bootstrap-1-fra.fil-test.net/tcp/1347/p2p/12D3KooW9szZmKttS9A1FafH3Zc2pxKwwmvCWCGKkRP4KmbhhC4R
|
||||
/ip4/136.144.49.131/tcp/1347/p2p/12D3KooW9szZmKttS9A1FafH3Zc2pxKwwmvCWCGKkRP4KmbhhC4R
|
||||
/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
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package build
|
||||
|
||||
import "github.com/raulk/clock"
|
||||
|
||||
// Clock is the global clock for the system. In standard builds,
|
||||
// we use a real-time clock, which maps to the `time` package.
|
||||
//
|
||||
// Tests that need control of time can replace this variable with
|
||||
// clock.NewMock(). Always use real time for socket/stream deadlines.
|
||||
var Clock = clock.New()
|
||||
@@ -0,0 +1,83 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
)
|
||||
|
||||
type DrandEnum int
|
||||
|
||||
func DrandConfigSchedule() dtypes.DrandSchedule {
|
||||
out := dtypes.DrandSchedule{}
|
||||
for start, config := range DrandSchedule {
|
||||
out = append(out, dtypes.DrandPoint{Start: start, Config: DrandConfigs[config]})
|
||||
}
|
||||
|
||||
sort.Slice(out, func(i, j int) bool {
|
||||
return out[i].Start < out[j].Start
|
||||
})
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
const (
|
||||
DrandMainnet DrandEnum = iota + 1
|
||||
DrandTestnet
|
||||
DrandDevnet
|
||||
DrandLocalnet
|
||||
DrandIncentinet
|
||||
)
|
||||
|
||||
var DrandConfigs = map[DrandEnum]dtypes.DrandConfig{
|
||||
DrandMainnet: {
|
||||
Servers: []string{
|
||||
"https://api.drand.sh",
|
||||
"https://api2.drand.sh",
|
||||
"https://api3.drand.sh",
|
||||
},
|
||||
Relays: []string{
|
||||
"/dnsaddr/api.drand.sh/",
|
||||
"/dnsaddr/api2.drand.sh/",
|
||||
"/dnsaddr/api3.drand.sh/",
|
||||
},
|
||||
ChainInfoJSON: `{"public_key":"868f005eb8e6e4ca0a47c8a77ceaa5309a47978a7c71bc5cce96366b5d7a569937c529eeda66c7293784a9402801af31","period":30,"genesis_time":1595431050,"hash":"8990e7a9aaed2ffed73dbd7092123d6f289930540d7651336225dc172e51b2ce","groupHash":"176f93498eac9ca337150b46d21dd58673ea4e3581185f869672e59fa4cb390a"}`,
|
||||
},
|
||||
DrandTestnet: {
|
||||
Servers: []string{
|
||||
"https://pl-eu.testnet.drand.sh",
|
||||
"https://pl-us.testnet.drand.sh",
|
||||
"https://pl-sin.testnet.drand.sh",
|
||||
},
|
||||
Relays: []string{
|
||||
"/dnsaddr/pl-eu.testnet.drand.sh/",
|
||||
"/dnsaddr/pl-us.testnet.drand.sh/",
|
||||
"/dnsaddr/pl-sin.testnet.drand.sh/",
|
||||
},
|
||||
ChainInfoJSON: `{"public_key":"922a2e93828ff83345bae533f5172669a26c02dc76d6bf59c80892e12ab1455c229211886f35bb56af6d5bea981024df","period":25,"genesis_time":1590445175,"hash":"84b2234fb34e835dccd048255d7ad3194b81af7d978c3bf157e3469592ae4e02","groupHash":"4dd408e5fdff9323c76a9b6f087ba8fdc5a6da907bd9217d9d10f2287d081957"}`,
|
||||
},
|
||||
DrandDevnet: {
|
||||
Servers: []string{
|
||||
"https://dev1.drand.sh",
|
||||
"https://dev2.drand.sh",
|
||||
},
|
||||
Relays: []string{
|
||||
"/dnsaddr/dev1.drand.sh/",
|
||||
"/dnsaddr/dev2.drand.sh/",
|
||||
},
|
||||
ChainInfoJSON: `{"public_key":"8cda589f88914aa728fd183f383980b35789ce81b274e5daee1f338b77d02566ef4d3fb0098af1f844f10f9c803c1827","period":25,"genesis_time":1595348225,"hash":"e73b7dc3c4f6a236378220c0dd6aa110eb16eed26c11259606e07ee122838d4f","groupHash":"567d4785122a5a3e75a9bc9911d7ea807dd85ff76b78dc4ff06b075712898607"}`,
|
||||
},
|
||||
DrandIncentinet: {
|
||||
Servers: []string{
|
||||
"https://pl-eu.incentinet.drand.sh",
|
||||
"https://pl-us.incentinet.drand.sh",
|
||||
"https://pl-sin.incentinet.drand.sh",
|
||||
},
|
||||
Relays: []string{
|
||||
"/dnsaddr/pl-eu.incentinet.drand.sh/",
|
||||
"/dnsaddr/pl-us.incentinet.drand.sh/",
|
||||
"/dnsaddr/pl-sin.incentinet.drand.sh/",
|
||||
},
|
||||
ChainInfoJSON: `{"public_key":"8cad0c72c606ab27d36ee06de1d5b2db1faf92e447025ca37575ab3a8aac2eaae83192f846fc9e158bc738423753d000","period":30,"genesis_time":1595873820,"hash":"80c8b872c714f4c00fdd3daa465d5514049f457f01f85a4caf68cdcd394ba039","groupHash":"d9406aaed487f7af71851b4399448e311f2328923d454e971536c05398ce2d9b"}`,
|
||||
},
|
||||
}
|
||||
Binary file not shown.
+13
-4
@@ -3,13 +3,22 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
)
|
||||
|
||||
const UpgradeBreezeHeight = -1
|
||||
const BreezeGasTampingDuration = 0
|
||||
|
||||
const UpgradeSmokeHeight = -1
|
||||
|
||||
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
||||
0: DrandMainnet,
|
||||
}
|
||||
|
||||
func init() {
|
||||
power.ConsensusMinerMinPower = big.NewInt(2048)
|
||||
miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
|
||||
@@ -20,9 +29,9 @@ func init() {
|
||||
BuildType |= Build2k
|
||||
}
|
||||
|
||||
const BlockDelaySecs = uint64(2)
|
||||
const BlockDelaySecs = uint64(30)
|
||||
|
||||
const PropagationDelaySecs = uint64(3)
|
||||
const PropagationDelaySecs = uint64(1)
|
||||
|
||||
// SlashablePowerDelay is the number of epochs after ElectionPeriodStart, after
|
||||
// which the miner is slashed
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
|
||||
"github.com/libp2p/go-libp2p-core/protocol"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
@@ -36,3 +36,11 @@ func MessagesTopic(netName dtypes.NetworkName) string { return "/fil/msgs/" + st
|
||||
func DhtProtocolName(netName dtypes.NetworkName) protocol.ID {
|
||||
return protocol.ID("/fil/kad/" + string(netName))
|
||||
}
|
||||
|
||||
func UseNewestNetwork() bool {
|
||||
// TODO: Put these in a container we can iterate over
|
||||
if UpgradeBreezeHeight <= 0 && UpgradeSmokeHeight <= 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
+20
-17
@@ -5,11 +5,11 @@ package build
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
)
|
||||
|
||||
// /////
|
||||
@@ -22,6 +22,7 @@ const UnixfsLinksPerLevel = 1024
|
||||
// Consensus / Network
|
||||
|
||||
const AllowableClockDriftSecs = uint64(1)
|
||||
const NewestNetworkVersion = network.Version2
|
||||
|
||||
// Epochs
|
||||
const ForkLengthThreshold = Finality
|
||||
@@ -30,7 +31,7 @@ const ForkLengthThreshold = Finality
|
||||
var BlocksPerEpoch = uint64(builtin.ExpectedLeadersPerEpoch)
|
||||
|
||||
// Epochs
|
||||
const Finality = miner.ChainFinalityish
|
||||
const Finality = miner.ChainFinality
|
||||
const MessageConfidence = uint64(5)
|
||||
|
||||
// constants for Weight calculation
|
||||
@@ -61,8 +62,8 @@ const WinningPoStSectorSetLookback = abi.ChainEpoch(10)
|
||||
// /////
|
||||
// Devnet settings
|
||||
|
||||
const TotalFilecoin = uint64(2_000_000_000)
|
||||
const MiningRewardTotal = uint64(1_400_000_000)
|
||||
const FilBase = uint64(2_000_000_000)
|
||||
const FilAllocStorageMining = uint64(1_100_000_000)
|
||||
|
||||
const FilecoinPrecision = uint64(1_000_000_000_000_000_000)
|
||||
|
||||
@@ -71,7 +72,7 @@ var InitialRewardBalance *big.Int
|
||||
// TODO: Move other important consts here
|
||||
|
||||
func init() {
|
||||
InitialRewardBalance = big.NewInt(int64(MiningRewardTotal))
|
||||
InitialRewardBalance = big.NewInt(int64(FilAllocStorageMining))
|
||||
InitialRewardBalance = InitialRewardBalance.Mul(InitialRewardBalance, big.NewInt(int64(FilecoinPrecision)))
|
||||
}
|
||||
|
||||
@@ -90,14 +91,16 @@ const VerifSigCacheSize = 32000
|
||||
// Limits
|
||||
|
||||
// TODO: If this is gonna stay, it should move to specs-actors
|
||||
const BlockMessageLimit = 512
|
||||
const BlockGasLimit = 100_000_000_000
|
||||
const BlockMessageLimit = 10000
|
||||
|
||||
var DrandConfig = dtypes.DrandConfig{
|
||||
Servers: []string{
|
||||
"https://pl-eu.testnet.drand.sh",
|
||||
"https://pl-us.testnet.drand.sh",
|
||||
"https://pl-sin.testnet.drand.sh",
|
||||
},
|
||||
ChainInfoJSON: `{"public_key":"922a2e93828ff83345bae533f5172669a26c02dc76d6bf59c80892e12ab1455c229211886f35bb56af6d5bea981024df","period":25,"genesis_time":1590445175,"hash":"138a324aa6540f93d0dad002aa89454b1bec2b6e948682cde6bd4db40f4b7c9b"}`,
|
||||
}
|
||||
const BlockGasLimit = 10_000_000_000
|
||||
const BlockGasTarget = BlockGasLimit / 2
|
||||
const BaseFeeMaxChangeDenom = 8 // 12.5%
|
||||
const InitialBaseFee = 100e6
|
||||
const MinimumBaseFee = 100
|
||||
const PackingEfficiencyNum = 4
|
||||
const PackingEfficiencyDenom = 5
|
||||
|
||||
// Actor consts
|
||||
// TODO: Pull from actors when its made not private
|
||||
var MinDealDuration = abi.ChainEpoch(180 * builtin.EpochsInDay)
|
||||
|
||||
+30
-19
@@ -10,9 +10,8 @@ package build
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
)
|
||||
@@ -21,15 +20,19 @@ var (
|
||||
UnixfsChunkSize = uint64(1 << 20)
|
||||
UnixfsLinksPerLevel = 1024
|
||||
|
||||
BlocksPerEpoch = uint64(builtin.ExpectedLeadersPerEpoch)
|
||||
BlockMessageLimit = 512
|
||||
BlockGasLimit = int64(100_000_000_000)
|
||||
BlockDelaySecs = uint64(builtin.EpochDurationSeconds)
|
||||
PropagationDelaySecs = uint64(6)
|
||||
BlocksPerEpoch = uint64(builtin.ExpectedLeadersPerEpoch)
|
||||
BlockMessageLimit = 512
|
||||
BlockGasLimit = int64(100_000_000_000)
|
||||
BlockGasTarget = int64(BlockGasLimit / 2)
|
||||
BaseFeeMaxChangeDenom = int64(8) // 12.5%
|
||||
InitialBaseFee = int64(100e6)
|
||||
MinimumBaseFee = int64(100)
|
||||
BlockDelaySecs = uint64(builtin.EpochDurationSeconds)
|
||||
PropagationDelaySecs = uint64(6)
|
||||
|
||||
AllowableClockDriftSecs = uint64(1)
|
||||
|
||||
Finality = miner.ChainFinalityish
|
||||
Finality = miner.ChainFinality
|
||||
ForkLengthThreshold = Finality
|
||||
|
||||
SlashablePowerDelay = 20
|
||||
@@ -51,23 +54,31 @@ var (
|
||||
TicketRandomnessLookback = abi.ChainEpoch(1)
|
||||
WinningPoStSectorSetLookback = abi.ChainEpoch(10)
|
||||
|
||||
TotalFilecoin uint64 = 2_000_000_000
|
||||
MiningRewardTotal uint64 = 1_400_000_000
|
||||
FilBase uint64 = 2_000_000_000
|
||||
FilAllocStorageMining uint64 = 1_400_000_000
|
||||
|
||||
FilecoinPrecision uint64 = 1_000_000_000_000_000_000
|
||||
|
||||
InitialRewardBalance = func() *big.Int {
|
||||
v := big.NewInt(int64(MiningRewardTotal))
|
||||
v := big.NewInt(int64(FilAllocStorageMining))
|
||||
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)
|
||||
|
||||
DrandConfig = dtypes.DrandConfig{
|
||||
Servers: []string{
|
||||
"https://pl-eu.testnet.drand.sh",
|
||||
"https://pl-us.testnet.drand.sh",
|
||||
"https://pl-sin.testnet.drand.sh",
|
||||
},
|
||||
ChainInfoJSON: `{"public_key":"922a2e93828ff83345bae533f5172669a26c02dc76d6bf59c80892e12ab1455c229211886f35bb56af6d5bea981024df","period":25,"genesis_time":1590445175,"hash":"138a324aa6540f93d0dad002aa89454b1bec2b6e948682cde6bd4db40f4b7c9b"}`,
|
||||
PackingEfficiencyNum int64 = 4
|
||||
PackingEfficiencyDenom int64 = 5
|
||||
|
||||
UpgradeBreezeHeight abi.ChainEpoch = -1
|
||||
BreezeGasTampingDuration abi.ChainEpoch = 0
|
||||
|
||||
UpgradeSmokeHeight abi.ChainEpoch = -1
|
||||
|
||||
DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
||||
0: DrandMainnet,
|
||||
}
|
||||
|
||||
NewestNetworkVersion = network.Version2
|
||||
)
|
||||
|
||||
+13
-3
@@ -5,15 +5,25 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
)
|
||||
|
||||
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
||||
0: DrandIncentinet,
|
||||
UpgradeSmokeHeight: DrandMainnet,
|
||||
}
|
||||
|
||||
const UpgradeBreezeHeight = 41280
|
||||
const BreezeGasTampingDuration = 120
|
||||
|
||||
const UpgradeSmokeHeight = 51000
|
||||
|
||||
func init() {
|
||||
power.ConsensusMinerMinPower = big.NewInt(1024 << 30)
|
||||
power.ConsensusMinerMinPower = big.NewInt(10 << 40)
|
||||
miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
|
||||
abi.RegisteredSealProof_StackedDrg32GiBV1: {},
|
||||
abi.RegisteredSealProof_StackedDrg64GiBV1: {},
|
||||
|
||||
@@ -1,152 +1,152 @@
|
||||
{
|
||||
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0170db1f394b35d995252228ee359194b13199d259380541dc529fb0099096b0.params": {
|
||||
"cid": "QmeDRyxek34F1H6xJY6AkFdWvPsy5F6dKTrebV3ZtWT4ky",
|
||||
"digest": "f5827f2d8801c62c831e0f972f6dc8bb",
|
||||
"v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0170db1f394b35d995252228ee359194b13199d259380541dc529fb0099096b0.params": {
|
||||
"cid": "QmVxjFRyhmyQaZEtCh7nk2abc7LhFkzhnRX4rcHqCCpikR",
|
||||
"digest": "7610b9f82bfc88405b7a832b651ce2f6",
|
||||
"sector_size": 2048
|
||||
},
|
||||
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0170db1f394b35d995252228ee359194b13199d259380541dc529fb0099096b0.vk": {
|
||||
"cid": "QmUw1ZmG4BBbX19MsbH3zAEGKUc42iFJc5ZAyomDHeJTsA",
|
||||
"digest": "398fecdb4b2de445125852bc3c080b35",
|
||||
"v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0170db1f394b35d995252228ee359194b13199d259380541dc529fb0099096b0.vk": {
|
||||
"cid": "QmcS5JZs8X3TdtkEBpHAdUYjdNDqcL7fWQFtQz69mpnu2X",
|
||||
"digest": "0e0958009936b9d5e515ec97b8cb792d",
|
||||
"sector_size": 2048
|
||||
},
|
||||
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0cfb4f178bbb71cf2ecfcd42accce558b27199ab4fb59cb78f2483fe21ef36d9.params": {
|
||||
"cid": "QmUeNKp9YZpiAFm81RV5KuxH1FDGJx2DuwcbU2XNSZLLSv",
|
||||
"digest": "2b6d2972ac9e862e8134d98fb695b0c5",
|
||||
"v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0cfb4f178bbb71cf2ecfcd42accce558b27199ab4fb59cb78f2483fe21ef36d9.params": {
|
||||
"cid": "QmUiRx71uxfmUE8V3H9sWAsAXoM88KR4eo1ByvvcFNeTLR",
|
||||
"digest": "1a7d4a9c8a502a497ed92a54366af33f",
|
||||
"sector_size": 536870912
|
||||
},
|
||||
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0cfb4f178bbb71cf2ecfcd42accce558b27199ab4fb59cb78f2483fe21ef36d9.vk": {
|
||||
"cid": "QmQaQmTXX995Akd66ggtJY5bNx6Gkxk8P34JTdMMq8393G",
|
||||
"digest": "3688c9eb256b7b17f411dad78d5ef74a",
|
||||
"v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0cfb4f178bbb71cf2ecfcd42accce558b27199ab4fb59cb78f2483fe21ef36d9.vk": {
|
||||
"cid": "QmfCeddjFpWtavzfEzZpJfzSajGNwfL4RjFXWAvA9TSnTV",
|
||||
"digest": "4dae975de4f011f101f5a2f86d1daaba",
|
||||
"sector_size": 536870912
|
||||
},
|
||||
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-3ea05428c9d11689f23529cde32fd30aabd50f7d2c93657c1d3650bca3e8ea9e.params": {
|
||||
"cid": "QmfEYTMSkwGJTumQx26iKXGNKiYh3mmAC4SkdybZpJCj5p",
|
||||
"digest": "09bff16aed893349d94485cfae366a9c",
|
||||
"v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-3ea05428c9d11689f23529cde32fd30aabd50f7d2c93657c1d3650bca3e8ea9e.params": {
|
||||
"cid": "QmcSTqDcFVLGGVYz1njhUZ7B6fkKtBumsLUwx4nkh22TzS",
|
||||
"digest": "82c88066be968bb550a05e30ff6c2413",
|
||||
"sector_size": 2048
|
||||
},
|
||||
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-3ea05428c9d11689f23529cde32fd30aabd50f7d2c93657c1d3650bca3e8ea9e.vk": {
|
||||
"cid": "QmP4ThPieSUJyRanjibWpT5R5cCMzMAU4j8Y7kBn7CSW1Q",
|
||||
"digest": "142f2f7e8f1b1779290315cabfd2c803",
|
||||
"v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-3ea05428c9d11689f23529cde32fd30aabd50f7d2c93657c1d3650bca3e8ea9e.vk": {
|
||||
"cid": "QmSTCXF2ipGA3f6muVo6kHc2URSx6PzZxGUqu7uykaH5KU",
|
||||
"digest": "ffd79788d614d27919ae5bd2d94eacb6",
|
||||
"sector_size": 2048
|
||||
},
|
||||
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-50c7368dea9593ed0989e70974d28024efa9d156d585b7eea1be22b2e753f331.params": {
|
||||
"cid": "QmcAixrHsz29DgvtZiMc2kQjvPRvWxYUp36QYmRDZbmREm",
|
||||
"digest": "8f987f64d434365562180b96ec12e299",
|
||||
"v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-50c7368dea9593ed0989e70974d28024efa9d156d585b7eea1be22b2e753f331.params": {
|
||||
"cid": "QmU9SBzJNrcjRFDiFc4GcApqdApN6z9X7MpUr66mJ2kAJP",
|
||||
"digest": "700171ecf7334e3199437c930676af82",
|
||||
"sector_size": 8388608
|
||||
},
|
||||
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-50c7368dea9593ed0989e70974d28024efa9d156d585b7eea1be22b2e753f331.vk": {
|
||||
"cid": "QmT4iFnbL6r4txS5PXsiV7NTzbhCxHy54PvdkJJGV2VFXb",
|
||||
"digest": "94b6c24ac01924f4feeecedd16b5d77d",
|
||||
"v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-50c7368dea9593ed0989e70974d28024efa9d156d585b7eea1be22b2e753f331.vk": {
|
||||
"cid": "QmbmUMa3TbbW3X5kFhExs6WgC4KeWT18YivaVmXDkB6ANG",
|
||||
"digest": "79ebb55f56fda427743e35053edad8fc",
|
||||
"sector_size": 8388608
|
||||
},
|
||||
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-5294475db5237a2e83c3e52fd6c2b03859a1831d45ed08c4f35dbf9a803165a9.params": {
|
||||
"cid": "QmbjFst6SFCK1KsTQrfwPdxf3VTNa1raed574tEZZ9PoyQ",
|
||||
"digest": "2c245fe8179839dd6c6cdea207c67ae8",
|
||||
"v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-5294475db5237a2e83c3e52fd6c2b03859a1831d45ed08c4f35dbf9a803165a9.params": {
|
||||
"cid": "QmdNEL2RtqL52GQNuj8uz6mVj5Z34NVnbaJ1yMyh1oXtBx",
|
||||
"digest": "c49499bb76a0762884896f9683403f55",
|
||||
"sector_size": 8388608
|
||||
},
|
||||
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-5294475db5237a2e83c3e52fd6c2b03859a1831d45ed08c4f35dbf9a803165a9.vk": {
|
||||
"cid": "QmQJKmvZN1a5cQ1Nw6CDyXs3nuRPzvyU5NvCFMUL2BfcZC",
|
||||
"digest": "56ae47bfda53bb8d22981ed8d8d27d72",
|
||||
"v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-5294475db5237a2e83c3e52fd6c2b03859a1831d45ed08c4f35dbf9a803165a9.vk": {
|
||||
"cid": "QmUiVYCQUgr6Y13pZFr8acWpSM4xvTXUdcvGmxyuHbKhsc",
|
||||
"digest": "34d4feeacd9abf788d69ef1bb4d8fd00",
|
||||
"sector_size": 8388608
|
||||
},
|
||||
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-7d739b8cf60f1b0709eeebee7730e297683552e4b69cab6984ec0285663c5781.params": {
|
||||
"cid": "QmQCABxeTpdvXTyjDyk7nPBxkQzCh7MXfGztWnSXEPKMLW",
|
||||
"digest": "7e6b2eb5ecbb11ac651ad66ebbb2075a",
|
||||
"v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-7d739b8cf60f1b0709eeebee7730e297683552e4b69cab6984ec0285663c5781.params": {
|
||||
"cid": "QmVgCsJFRXKLuuUhT3aMYwKVGNA9rDeR6DCrs7cAe8riBT",
|
||||
"digest": "827359440349fe8f5a016e7598993b79",
|
||||
"sector_size": 536870912
|
||||
},
|
||||
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-7d739b8cf60f1b0709eeebee7730e297683552e4b69cab6984ec0285663c5781.vk": {
|
||||
"cid": "QmPBweyugh5Sx4umk8ULhgEGbjY8xmWLfU6M7EMpc8Mad6",
|
||||
"digest": "94a8d9e25a9ab9674d339833664eba25",
|
||||
"v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-7d739b8cf60f1b0709eeebee7730e297683552e4b69cab6984ec0285663c5781.vk": {
|
||||
"cid": "QmfA31fbCWojSmhSGvvfxmxaYCpMoXP95zEQ9sLvBGHNaN",
|
||||
"digest": "bd2cd62f65c1ab84f19ca27e97b7c731",
|
||||
"sector_size": 536870912
|
||||
},
|
||||
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-0377ded656c6f524f1618760bffe4e0a1c51d5a70c4509eedae8a27555733edc.params": {
|
||||
"cid": "QmY5yax1E9KymBnCeHksE9Zi8NieZbmwcpoDGoabkeeb9h",
|
||||
"digest": "c909ea9e3fe25ab9b391a64593afdbba",
|
||||
"v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-0377ded656c6f524f1618760bffe4e0a1c51d5a70c4509eedae8a27555733edc.params": {
|
||||
"cid": "QmaUmfcJt6pozn8ndq1JVBzLRjRJdHMTPd4foa8iw5sjBZ",
|
||||
"digest": "2cf49eb26f1fee94c85781a390ddb4c8",
|
||||
"sector_size": 34359738368
|
||||
},
|
||||
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-0377ded656c6f524f1618760bffe4e0a1c51d5a70c4509eedae8a27555733edc.vk": {
|
||||
"cid": "QmXnPo4yH5mwMguwrvqgRfduSttbmPrXtbBfbwU21wQWHt",
|
||||
"digest": "caf900461e988bbf86dbcaca087b7864",
|
||||
"v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-0377ded656c6f524f1618760bffe4e0a1c51d5a70c4509eedae8a27555733edc.vk": {
|
||||
"cid": "QmR9i9KL3vhhAqTBGj1bPPC7LvkptxrH9RvxJxLN1vvsBE",
|
||||
"digest": "0f8ec542485568fa3468c066e9fed82b",
|
||||
"sector_size": 34359738368
|
||||
},
|
||||
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-559e581f022bb4e4ec6e719e563bf0e026ad6de42e56c18714a2c692b1b88d7e.params": {
|
||||
"cid": "QmZtzzPWwmZEgR7MSMvXRbt9KVK8k4XZ5RLWHybHJW9SdE",
|
||||
"digest": "a2844f0703f186d143a06146a04577d8",
|
||||
"v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-559e581f022bb4e4ec6e719e563bf0e026ad6de42e56c18714a2c692b1b88d7e.params": {
|
||||
"cid": "Qmdtczp7p4wrbDofmHdGhiixn9irAcN77mV9AEHZBaTt1i",
|
||||
"digest": "d84f79a16fe40e9e25a36e2107bb1ba0",
|
||||
"sector_size": 34359738368
|
||||
},
|
||||
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-559e581f022bb4e4ec6e719e563bf0e026ad6de42e56c18714a2c692b1b88d7e.vk": {
|
||||
"cid": "QmWxEA7EdQCUJTzjNpxg5XTF45D2uVyYnN1QRUb5TRYU8M",
|
||||
"digest": "2306247a1e616dbe07f01b88196c2044",
|
||||
"v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-559e581f022bb4e4ec6e719e563bf0e026ad6de42e56c18714a2c692b1b88d7e.vk": {
|
||||
"cid": "QmZCvxKcKP97vDAk8Nxs9R1fWtqpjQrAhhfXPoCi1nkDoF",
|
||||
"digest": "fc02943678dd119e69e7fab8420e8819",
|
||||
"sector_size": 34359738368
|
||||
},
|
||||
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-2627e4006b67f99cef990c0a47d5426cb7ab0a0ad58fc1061547bf2d28b09def.params": {
|
||||
"cid": "QmP676KwuvyF9Y64uJnXvLtvD1xcuWQ6wD23RzYtQ6dd4f",
|
||||
"digest": "215b1c667a4f46a1d0178338df568615",
|
||||
"v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-2627e4006b67f99cef990c0a47d5426cb7ab0a0ad58fc1061547bf2d28b09def.params": {
|
||||
"cid": "QmeAN4vuANhXsF8xP2Lx5j2L6yMSdogLzpcvqCJThRGK1V",
|
||||
"digest": "3810b7780ac0e299b22ae70f1f94c9bc",
|
||||
"sector_size": 68719476736
|
||||
},
|
||||
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-2627e4006b67f99cef990c0a47d5426cb7ab0a0ad58fc1061547bf2d28b09def.vk": {
|
||||
"cid": "QmPvPwbJtcSGyqB1rQJhSF5yvFbX9ZBSsHVej5F8JUyHUJ",
|
||||
"digest": "0c9c423b28b1455fcbc329a1045fd4dd",
|
||||
"v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-2627e4006b67f99cef990c0a47d5426cb7ab0a0ad58fc1061547bf2d28b09def.vk": {
|
||||
"cid": "QmWV8rqZLxs1oQN9jxNWmnT1YdgLwCcscv94VARrhHf1T7",
|
||||
"digest": "59d2bf1857adc59a4f08fcf2afaa916b",
|
||||
"sector_size": 68719476736
|
||||
},
|
||||
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-b62098629d07946e9028127e70295ed996fe3ed25b0f9f88eb610a0ab4385a3c.params": {
|
||||
"cid": "QmUxPQfvckzm1t6MFRdDZ1fDK5UJzAjK7pTZ97cwyachdr",
|
||||
"digest": "965132f51ae445b0e6d32692b7561995",
|
||||
"v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-b62098629d07946e9028127e70295ed996fe3ed25b0f9f88eb610a0ab4385a3c.params": {
|
||||
"cid": "QmVkrXc1SLcpgcudK5J25HH93QvR9tNsVhVTYHm5UymXAz",
|
||||
"digest": "2170a91ad5bae22ea61f2ea766630322",
|
||||
"sector_size": 68719476736
|
||||
},
|
||||
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-b62098629d07946e9028127e70295ed996fe3ed25b0f9f88eb610a0ab4385a3c.vk": {
|
||||
"cid": "QmTxq2EBnQWb5R8tS4MHdchj4vNfLYGoSXxwJFvs5xgW4K",
|
||||
"digest": "fc8c3d26e0e56373ad96cb41520d55a6",
|
||||
"v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-b62098629d07946e9028127e70295ed996fe3ed25b0f9f88eb610a0ab4385a3c.vk": {
|
||||
"cid": "QmbfQjPD7EpzjhWGmvWAsyN2mAZ4PcYhsf3ujuhU9CSuBm",
|
||||
"digest": "6d3789148fb6466d07ee1e24d6292fd6",
|
||||
"sector_size": 68719476736
|
||||
},
|
||||
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-032d3138d22506ec0082ed72b2dcba18df18477904e35bafee82b3793b06832f.params": {
|
||||
"cid": "QmRjgZHERgqGoRagR788Kh6ybi26csVYa8mqbqhmZm57Jx",
|
||||
"digest": "cfc7b0897d1eee48c586f7beb89e67f7",
|
||||
"v28-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-032d3138d22506ec0082ed72b2dcba18df18477904e35bafee82b3793b06832f.params": {
|
||||
"cid": "QmWceMgnWYLopMuM4AoGMvGEau7tNe5UK83XFjH5V9B17h",
|
||||
"digest": "434fb1338ecfaf0f59256f30dde4968f",
|
||||
"sector_size": 2048
|
||||
},
|
||||
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-032d3138d22506ec0082ed72b2dcba18df18477904e35bafee82b3793b06832f.vk": {
|
||||
"cid": "QmNjvnvFP7KgovHUddULoB19fBHT81iz7NcUbzEHZUUPsm",
|
||||
"digest": "fb59bd061c987eac7068008c44de346b",
|
||||
"v28-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-032d3138d22506ec0082ed72b2dcba18df18477904e35bafee82b3793b06832f.vk": {
|
||||
"cid": "QmamahpFCstMUqHi2qGtVoDnRrsXhid86qsfvoyCTKJqHr",
|
||||
"digest": "dc1ade9929ade1708238f155343044ac",
|
||||
"sector_size": 2048
|
||||
},
|
||||
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-6babf46ce344ae495d558e7770a585b2382d54f225af8ed0397b8be7c3fcd472.params": {
|
||||
"cid": "QmTpRPBA4dt8fgGpcVzi4L1KA1U2eBHCE8WVmS2GUygMvT",
|
||||
"digest": "36d465915b0afbf96bd08e7915e00952",
|
||||
"v28-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-6babf46ce344ae495d558e7770a585b2382d54f225af8ed0397b8be7c3fcd472.params": {
|
||||
"cid": "QmYBpTt7LWNAWr1JXThV5VxX7wsQFLd1PHrGYVbrU1EZjC",
|
||||
"digest": "6c77597eb91ab936c1cef4cf19eba1b3",
|
||||
"sector_size": 536870912
|
||||
},
|
||||
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-6babf46ce344ae495d558e7770a585b2382d54f225af8ed0397b8be7c3fcd472.vk": {
|
||||
"cid": "QmRzDyVfQCLsxspoVsed5bcQRsG6KiktngJfcNBL3TJPZe",
|
||||
"digest": "99d16df0eb6a7e227a4f4570c4f6b6f1",
|
||||
"v28-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-6babf46ce344ae495d558e7770a585b2382d54f225af8ed0397b8be7c3fcd472.vk": {
|
||||
"cid": "QmWionkqH2B6TXivzBSQeSyBxojaiAFbzhjtwYRrfwd8nH",
|
||||
"digest": "065179da19fbe515507267677f02823e",
|
||||
"sector_size": 536870912
|
||||
},
|
||||
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-ecd683648512ab1765faa2a5f14bab48f676e633467f0aa8aad4b55dcb0652bb.params": {
|
||||
"cid": "QmV8ZjTSGzDUWmFvsq9NSyPBR7eDDUcvCPNgj2yE7HMAFu",
|
||||
"digest": "34f3ddf1d1c9f41c0cd73b91e8b4bc27",
|
||||
"v28-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-ecd683648512ab1765faa2a5f14bab48f676e633467f0aa8aad4b55dcb0652bb.params": {
|
||||
"cid": "QmPXAPPuQtuQz7Zz3MHMAMEtsYwqM1o9H1csPLeiMUQwZH",
|
||||
"digest": "09e612e4eeb7a0eb95679a88404f960c",
|
||||
"sector_size": 8388608
|
||||
},
|
||||
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-ecd683648512ab1765faa2a5f14bab48f676e633467f0aa8aad4b55dcb0652bb.vk": {
|
||||
"cid": "QmTa3VbjTiqJWU6r4WKayaQrUaaBsrpp5UDqYvPDd2C5hs",
|
||||
"digest": "ec62d59651daa5631d3d1e9c782dd940",
|
||||
"v28-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-ecd683648512ab1765faa2a5f14bab48f676e633467f0aa8aad4b55dcb0652bb.vk": {
|
||||
"cid": "QmYCuipFyvVW1GojdMrjK1JnMobXtT4zRCZs1CGxjizs99",
|
||||
"digest": "b687beb9adbd9dabe265a7e3620813e4",
|
||||
"sector_size": 8388608
|
||||
},
|
||||
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-0-sha256_hasher-82a357d2f2ca81dc61bb45f4a762807aedee1b0a53fd6c4e77b46a01bfef7820.params": {
|
||||
"cid": "Qmf8ngfArxrv9tFWDqBcNegdBMymvuakwyHKd1pbW3pbsb",
|
||||
"digest": "a16d6f4c6424fb280236739f84b24f97",
|
||||
"v28-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-0-sha256_hasher-82a357d2f2ca81dc61bb45f4a762807aedee1b0a53fd6c4e77b46a01bfef7820.params": {
|
||||
"cid": "QmengpM684XLQfG8754ToonszgEg2bQeAGUan5uXTHUQzJ",
|
||||
"digest": "6a388072a518cf46ebd661f5cc46900a",
|
||||
"sector_size": 34359738368
|
||||
},
|
||||
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-0-sha256_hasher-82a357d2f2ca81dc61bb45f4a762807aedee1b0a53fd6c4e77b46a01bfef7820.vk": {
|
||||
"cid": "QmfQgVFerArJ6Jupwyc9tKjLD9n1J9ajLHBdpY465tRM7M",
|
||||
"digest": "7a139d82b8a02e35279d657e197f5c1f",
|
||||
"v28-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-0-sha256_hasher-82a357d2f2ca81dc61bb45f4a762807aedee1b0a53fd6c4e77b46a01bfef7820.vk": {
|
||||
"cid": "Qmf93EMrADXAK6CyiSfE8xx45fkMfR3uzKEPCvZC1n2kzb",
|
||||
"digest": "0c7b4aac1c40fdb7eb82bc355b41addf",
|
||||
"sector_size": 34359738368
|
||||
},
|
||||
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-2-sha256_hasher-96f1b4a04c5c51e4759bbf224bbc2ef5a42c7100f16ec0637123f16a845ddfb2.params": {
|
||||
"cid": "QmfDha8271nXJn14Aq3qQeghjMBWbs6HNSGa6VuzCVk4TW",
|
||||
"digest": "5d3cd3f107a3bea8a96d1189efd2965c",
|
||||
"v28-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-2-sha256_hasher-96f1b4a04c5c51e4759bbf224bbc2ef5a42c7100f16ec0637123f16a845ddfb2.params": {
|
||||
"cid": "QmS7ye6Ri2MfFzCkcUJ7FQ6zxDKuJ6J6B8k5PN7wzSR9sX",
|
||||
"digest": "1801f8a6e1b00bceb00cc27314bb5ce3",
|
||||
"sector_size": 68719476736
|
||||
},
|
||||
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-2-sha256_hasher-96f1b4a04c5c51e4759bbf224bbc2ef5a42c7100f16ec0637123f16a845ddfb2.vk": {
|
||||
"cid": "QmRVtTtiFzHJTHurYzaCvetGAchux9cktixT4aGHthN6Zt",
|
||||
"digest": "62c366405404e60f171e661492740b1c",
|
||||
"v28-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-2-sha256_hasher-96f1b4a04c5c51e4759bbf224bbc2ef5a42c7100f16ec0637123f16a845ddfb2.vk": {
|
||||
"cid": "QmehSmC6BhrgRZakPDta2ewoH9nosNzdjCqQRXsNFNUkLN",
|
||||
"digest": "a89884252c04c298d0b3c81bfd884164",
|
||||
"sector_size": 68719476736
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+37
-4
@@ -1,6 +1,10 @@
|
||||
package build
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
var CurrentCommit string
|
||||
var BuildType int
|
||||
@@ -25,7 +29,7 @@ func buildType() string {
|
||||
}
|
||||
|
||||
// BuildVersion is the local build version, set by build system
|
||||
const BuildVersion = "0.4.1"
|
||||
const BuildVersion = "0.7.0"
|
||||
|
||||
func UserVersion() string {
|
||||
return BuildVersion + buildType() + CurrentCommit
|
||||
@@ -52,8 +56,37 @@ func (ve Version) EqMajorMinor(v2 Version) bool {
|
||||
return ve&minorMask == v2&minorMask
|
||||
}
|
||||
|
||||
// APIVersion is a semver version of the rpc api exposed
|
||||
var APIVersion Version = newVer(0, 6, 0)
|
||||
type NodeType int
|
||||
|
||||
const (
|
||||
NodeUnknown NodeType = iota
|
||||
|
||||
NodeFull
|
||||
NodeMiner
|
||||
NodeWorker
|
||||
)
|
||||
|
||||
var RunningNodeType NodeType
|
||||
|
||||
func VersionForType(nodeType NodeType) (Version, error) {
|
||||
switch nodeType {
|
||||
case NodeFull:
|
||||
return FullAPIVersion, nil
|
||||
case NodeMiner:
|
||||
return MinerAPIVersion, nil
|
||||
case NodeWorker:
|
||||
return WorkerAPIVersion, nil
|
||||
default:
|
||||
return Version(0), xerrors.Errorf("unknown node type %d", nodeType)
|
||||
}
|
||||
}
|
||||
|
||||
// semver versions of the rpc api exposed
|
||||
var (
|
||||
FullAPIVersion = newVer(0, 14, 0)
|
||||
MinerAPIVersion = newVer(0, 14, 0)
|
||||
WorkerAPIVersion = newVer(0, 14, 0)
|
||||
)
|
||||
|
||||
//nolint:varcheck,deadcode
|
||||
const (
|
||||
|
||||
@@ -3,7 +3,7 @@ package aerrors
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
||||
"github.com/filecoin-project/go-state-types/exitcode"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ package aerrors_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/exitcode"
|
||||
. "github.com/filecoin-project/lotus/chain/actors/aerrors"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
||||
"github.com/filecoin-project/go-state-types/exitcode"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
@@ -56,6 +56,10 @@ func (bts *BadBlockCache) Add(c cid.Cid, bbr BadBlockReason) {
|
||||
bts.badBlocks.Add(c, bbr)
|
||||
}
|
||||
|
||||
func (bts *BadBlockCache) Remove(c cid.Cid) {
|
||||
bts.badBlocks.Remove(c)
|
||||
}
|
||||
|
||||
func (bts *BadBlockCache) Has(c cid.Cid) (BadBlockReason, bool) {
|
||||
rval, ok := bts.badBlocks.Get(c)
|
||||
if !ok {
|
||||
|
||||
+77
-11
@@ -2,12 +2,13 @@ package beacon
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
logging "github.com/ipfs/go-log"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
var log = logging.Logger("beacon")
|
||||
@@ -17,6 +18,23 @@ type Response struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
type Schedule []BeaconPoint
|
||||
|
||||
func (bs Schedule) BeaconForEpoch(e abi.ChainEpoch) RandomBeacon {
|
||||
for i := len(bs) - 1; i >= 0; i-- {
|
||||
bp := bs[i]
|
||||
if e >= bp.Start {
|
||||
return bp.Beacon
|
||||
}
|
||||
}
|
||||
return bs[0].Beacon
|
||||
}
|
||||
|
||||
type BeaconPoint struct {
|
||||
Start abi.ChainEpoch
|
||||
Beacon RandomBeacon
|
||||
}
|
||||
|
||||
// RandomBeacon represents a system that provides randomness to Lotus.
|
||||
// Other components interrogate the RandomBeacon to acquire randomness that's
|
||||
// valid for a specific chain epoch. Also to verify beacon entries that have
|
||||
@@ -24,11 +42,30 @@ type Response struct {
|
||||
type RandomBeacon interface {
|
||||
Entry(context.Context, uint64) <-chan Response
|
||||
VerifyEntry(types.BeaconEntry, types.BeaconEntry) error
|
||||
MaxBeaconRoundForEpoch(abi.ChainEpoch, types.BeaconEntry) uint64
|
||||
MaxBeaconRoundForEpoch(abi.ChainEpoch) uint64
|
||||
}
|
||||
|
||||
func ValidateBlockValues(b RandomBeacon, h *types.BlockHeader, prevEntry types.BeaconEntry) error {
|
||||
maxRound := b.MaxBeaconRoundForEpoch(h.Height, prevEntry)
|
||||
func ValidateBlockValues(bSchedule Schedule, h *types.BlockHeader, parentEpoch abi.ChainEpoch,
|
||||
prevEntry types.BeaconEntry) error {
|
||||
{
|
||||
parentBeacon := bSchedule.BeaconForEpoch(parentEpoch)
|
||||
currBeacon := bSchedule.BeaconForEpoch(h.Height)
|
||||
if parentBeacon != currBeacon {
|
||||
if len(h.BeaconEntries) != 2 {
|
||||
return xerrors.Errorf("expected two beacon entries at beacon fork, got %d", len(h.BeaconEntries))
|
||||
}
|
||||
err := currBeacon.VerifyEntry(h.BeaconEntries[1], h.BeaconEntries[0])
|
||||
if err != nil {
|
||||
return xerrors.Errorf("beacon at fork point invalid: (%v, %v): %w",
|
||||
h.BeaconEntries[1], h.BeaconEntries[0], err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: fork logic
|
||||
b := bSchedule.BeaconForEpoch(h.Height)
|
||||
maxRound := b.MaxBeaconRoundForEpoch(h.Height)
|
||||
if maxRound == prevEntry.Round {
|
||||
if len(h.BeaconEntries) != 0 {
|
||||
return xerrors.Errorf("expected not to have any beacon entries in this block, got %d", len(h.BeaconEntries))
|
||||
@@ -36,6 +73,10 @@ func ValidateBlockValues(b RandomBeacon, h *types.BlockHeader, prevEntry types.B
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(h.BeaconEntries) == 0 {
|
||||
return xerrors.Errorf("expected to have beacon entries in this block, but didn't find any")
|
||||
}
|
||||
|
||||
last := h.BeaconEntries[len(h.BeaconEntries)-1]
|
||||
if last.Round != maxRound {
|
||||
return xerrors.Errorf("expected final beacon entry in block to be at round %d, got %d", maxRound, last.Round)
|
||||
@@ -51,10 +92,35 @@ func ValidateBlockValues(b RandomBeacon, h *types.BlockHeader, prevEntry types.B
|
||||
return nil
|
||||
}
|
||||
|
||||
func BeaconEntriesForBlock(ctx context.Context, beacon RandomBeacon, round abi.ChainEpoch, prev types.BeaconEntry) ([]types.BeaconEntry, error) {
|
||||
start := time.Now()
|
||||
func BeaconEntriesForBlock(ctx context.Context, bSchedule Schedule, epoch abi.ChainEpoch, parentEpoch abi.ChainEpoch, prev types.BeaconEntry) ([]types.BeaconEntry, error) {
|
||||
{
|
||||
parentBeacon := bSchedule.BeaconForEpoch(parentEpoch)
|
||||
currBeacon := bSchedule.BeaconForEpoch(epoch)
|
||||
if parentBeacon != currBeacon {
|
||||
// Fork logic
|
||||
round := currBeacon.MaxBeaconRoundForEpoch(epoch)
|
||||
out := make([]types.BeaconEntry, 2)
|
||||
rch := currBeacon.Entry(ctx, round-1)
|
||||
res := <-rch
|
||||
if res.Err != nil {
|
||||
return nil, xerrors.Errorf("getting entry %d returned error: %w", round-1, res.Err)
|
||||
}
|
||||
out[0] = res.Entry
|
||||
rch = currBeacon.Entry(ctx, round)
|
||||
res = <-rch
|
||||
if res.Err != nil {
|
||||
return nil, xerrors.Errorf("getting entry %d returned error: %w", round, res.Err)
|
||||
}
|
||||
out[1] = res.Entry
|
||||
return out, nil
|
||||
}
|
||||
}
|
||||
|
||||
maxRound := beacon.MaxBeaconRoundForEpoch(round, prev)
|
||||
beacon := bSchedule.BeaconForEpoch(epoch)
|
||||
|
||||
start := build.Clock.Now()
|
||||
|
||||
maxRound := beacon.MaxBeaconRoundForEpoch(epoch)
|
||||
if maxRound == prev.Round {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -77,11 +143,11 @@ func BeaconEntriesForBlock(ctx context.Context, beacon RandomBeacon, round abi.C
|
||||
out = append(out, resp.Entry)
|
||||
cur = resp.Entry.Round - 1
|
||||
case <-ctx.Done():
|
||||
return nil, xerrors.Errorf("context timed out waiting on beacon entry to come back for round %d: %w", round, ctx.Err())
|
||||
return nil, xerrors.Errorf("context timed out waiting on beacon entry to come back for epoch %d: %w", epoch, ctx.Err())
|
||||
}
|
||||
}
|
||||
|
||||
log.Debugw("fetching beacon entries", "took", time.Since(start), "numEntries", len(out))
|
||||
log.Debugw("fetching beacon entries", "took", build.Clock.Since(start), "numEntries", len(out))
|
||||
reverse(out)
|
||||
return out, nil
|
||||
}
|
||||
|
||||
@@ -19,8 +19,9 @@ import (
|
||||
logging "github.com/ipfs/go-log"
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/beacon"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
@@ -131,7 +132,7 @@ func (db *DrandBeacon) Entry(ctx context.Context, round uint64) <-chan beacon.Re
|
||||
}
|
||||
|
||||
go func() {
|
||||
start := time.Now()
|
||||
start := build.Clock.Now()
|
||||
log.Infow("start fetching randomness", "round", round)
|
||||
resp, err := db.client.Get(ctx, round)
|
||||
|
||||
@@ -142,7 +143,7 @@ func (db *DrandBeacon) Entry(ctx context.Context, round uint64) <-chan beacon.Re
|
||||
br.Entry.Round = resp.Round()
|
||||
br.Entry.Data = resp.Signature()
|
||||
}
|
||||
log.Infow("done fetching randomness", "round", round, "took", time.Since(start))
|
||||
log.Infow("done fetching randomness", "round", round, "took", build.Clock.Since(start))
|
||||
out <- br
|
||||
close(out)
|
||||
}()
|
||||
@@ -170,6 +171,10 @@ func (db *DrandBeacon) VerifyEntry(curr types.BeaconEntry, prev types.BeaconEntr
|
||||
// TODO handle genesis better
|
||||
return nil
|
||||
}
|
||||
if be := db.getCachedValue(curr.Round); be != nil {
|
||||
// return no error if the value is in the cache already
|
||||
return nil
|
||||
}
|
||||
b := &dchain.Beacon{
|
||||
PreviousSig: prev.Data,
|
||||
Round: curr.Round,
|
||||
@@ -182,7 +187,7 @@ func (db *DrandBeacon) VerifyEntry(curr types.BeaconEntry, prev types.BeaconEntr
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DrandBeacon) MaxBeaconRoundForEpoch(filEpoch abi.ChainEpoch, prevEntry types.BeaconEntry) uint64 {
|
||||
func (db *DrandBeacon) MaxBeaconRoundForEpoch(filEpoch abi.ChainEpoch) uint64 {
|
||||
// TODO: sometimes the genesis time for filecoin is zero and this goes negative
|
||||
latestTs := ((uint64(filEpoch) * db.filRoundTime) + db.filGenTime) - db.filRoundTime
|
||||
dround := (latestTs - db.drandGenTime) / uint64(db.interval.Seconds())
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
func TestPrintGroupInfo(t *testing.T) {
|
||||
server := build.DrandConfig.Servers[0]
|
||||
server := build.DrandConfigs[build.DrandIncentinet].Servers[0]
|
||||
c, err := hclient.New(server, nil, nil)
|
||||
assert.NoError(t, err)
|
||||
cg := c.(interface {
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
"encoding/binary"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/minio/blake2b-simd"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
@@ -53,11 +53,7 @@ func (mb *mockBeacon) VerifyEntry(from types.BeaconEntry, to types.BeaconEntry)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mb *mockBeacon) IsEntryForEpoch(e types.BeaconEntry, epoch abi.ChainEpoch, nulls int) (bool, error) {
|
||||
return int64(e.Round) <= int64(epoch) && int64(epoch)-int64(nulls) >= int64(e.Round), nil
|
||||
}
|
||||
|
||||
func (mb *mockBeacon) MaxBeaconRoundForEpoch(epoch abi.ChainEpoch, prevEntry types.BeaconEntry) uint64 {
|
||||
func (mb *mockBeacon) MaxBeaconRoundForEpoch(epoch abi.ChainEpoch) uint64 {
|
||||
return uint64(epoch)
|
||||
}
|
||||
|
||||
|
||||
@@ -5,9 +5,10 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/hashicorp/golang-lru"
|
||||
peer "github.com/libp2p/go-libp2p-core/peer"
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
)
|
||||
|
||||
type blockReceiptTracker struct {
|
||||
@@ -37,14 +38,14 @@ func (brt *blockReceiptTracker) Add(p peer.ID, ts *types.TipSet) {
|
||||
if !ok {
|
||||
pset := &peerSet{
|
||||
peers: map[peer.ID]time.Time{
|
||||
p: time.Now(),
|
||||
p: build.Clock.Now(),
|
||||
},
|
||||
}
|
||||
brt.cache.Add(ts.Key(), pset)
|
||||
return
|
||||
}
|
||||
|
||||
val.(*peerSet).peers[p] = time.Now()
|
||||
val.(*peerSet).peers[p] = build.Clock.Now()
|
||||
}
|
||||
|
||||
func (brt *blockReceiptTracker) GetPeers(ts *types.TipSet) []peer.ID {
|
||||
|
||||
@@ -1,276 +0,0 @@
|
||||
package blocksync
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/libp2p/go-libp2p-core/protocol"
|
||||
"go.opencensus.io/trace"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
cborutil "github.com/filecoin-project/go-cbor-util"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
inet "github.com/libp2p/go-libp2p-core/network"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
)
|
||||
|
||||
var log = logging.Logger("blocksync")
|
||||
|
||||
type NewStreamFunc func(context.Context, peer.ID, ...protocol.ID) (inet.Stream, error)
|
||||
|
||||
const BlockSyncProtocolID = "/fil/sync/blk/0.0.1"
|
||||
|
||||
const BlockSyncMaxRequestLength = 800
|
||||
|
||||
// BlockSyncService is the component that services BlockSync requests from
|
||||
// peers.
|
||||
//
|
||||
// BlockSync is the basic chain synchronization protocol of Filecoin. BlockSync
|
||||
// is an RPC-oriented protocol, with a single operation to request blocks.
|
||||
//
|
||||
// A request contains a start anchor block (referred to with a CID), and a
|
||||
// amount of blocks requested beyond the anchor (including the anchor itself).
|
||||
//
|
||||
// A client can also pass options, encoded as a 64-bit bitfield. Lotus supports
|
||||
// two options at the moment:
|
||||
//
|
||||
// - include block contents
|
||||
// - include block messages
|
||||
//
|
||||
// The response will include a status code, an optional message, and the
|
||||
// response payload in case of success. The payload is a slice of serialized
|
||||
// tipsets.
|
||||
type BlockSyncService struct {
|
||||
cs *store.ChainStore
|
||||
}
|
||||
|
||||
type BlockSyncRequest struct {
|
||||
Start []cid.Cid
|
||||
RequestLength uint64
|
||||
|
||||
Options uint64
|
||||
}
|
||||
|
||||
type BSOptions struct {
|
||||
IncludeBlocks bool
|
||||
IncludeMessages bool
|
||||
}
|
||||
|
||||
func ParseBSOptions(optfield uint64) *BSOptions {
|
||||
return &BSOptions{
|
||||
IncludeBlocks: optfield&(BSOptBlocks) != 0,
|
||||
IncludeMessages: optfield&(BSOptMessages) != 0,
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
BSOptBlocks = 1 << iota
|
||||
BSOptMessages
|
||||
)
|
||||
|
||||
const (
|
||||
StatusOK = uint64(0)
|
||||
StatusPartial = uint64(101)
|
||||
StatusNotFound = uint64(201)
|
||||
StatusGoAway = uint64(202)
|
||||
StatusInternalError = uint64(203)
|
||||
StatusBadRequest = uint64(204)
|
||||
)
|
||||
|
||||
type BlockSyncResponse struct {
|
||||
Chain []*BSTipSet
|
||||
|
||||
Status uint64
|
||||
Message string
|
||||
}
|
||||
|
||||
type BSTipSet struct {
|
||||
Blocks []*types.BlockHeader
|
||||
|
||||
BlsMessages []*types.Message
|
||||
BlsMsgIncludes [][]uint64
|
||||
|
||||
SecpkMessages []*types.SignedMessage
|
||||
SecpkMsgIncludes [][]uint64
|
||||
}
|
||||
|
||||
func NewBlockSyncService(cs *store.ChainStore) *BlockSyncService {
|
||||
return &BlockSyncService{
|
||||
cs: cs,
|
||||
}
|
||||
}
|
||||
|
||||
func (bss *BlockSyncService) HandleStream(s inet.Stream) {
|
||||
ctx, span := trace.StartSpan(context.Background(), "blocksync.HandleStream")
|
||||
defer span.End()
|
||||
|
||||
defer s.Close() //nolint:errcheck
|
||||
|
||||
var req BlockSyncRequest
|
||||
if err := cborutil.ReadCborRPC(bufio.NewReader(s), &req); err != nil {
|
||||
log.Warnf("failed to read block sync request: %s", err)
|
||||
return
|
||||
}
|
||||
log.Infow("block sync request", "start", req.Start, "len", req.RequestLength)
|
||||
|
||||
resp, err := bss.processRequest(ctx, s.Conn().RemotePeer(), &req)
|
||||
if err != nil {
|
||||
log.Warn("failed to process block sync request: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
writeDeadline := 60 * time.Second
|
||||
_ = s.SetDeadline(time.Now().Add(writeDeadline))
|
||||
if err := cborutil.WriteCborRPC(s, resp); err != nil {
|
||||
log.Warnw("failed to write back response for handle stream", "err", err, "peer", s.Conn().RemotePeer())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (bss *BlockSyncService) processRequest(ctx context.Context, p peer.ID, req *BlockSyncRequest) (*BlockSyncResponse, error) {
|
||||
_, span := trace.StartSpan(ctx, "blocksync.ProcessRequest")
|
||||
defer span.End()
|
||||
|
||||
opts := ParseBSOptions(req.Options)
|
||||
if len(req.Start) == 0 {
|
||||
return &BlockSyncResponse{
|
||||
Status: StatusBadRequest,
|
||||
Message: "no cids given in blocksync request",
|
||||
}, nil
|
||||
}
|
||||
|
||||
span.AddAttributes(
|
||||
trace.BoolAttribute("blocks", opts.IncludeBlocks),
|
||||
trace.BoolAttribute("messages", opts.IncludeMessages),
|
||||
trace.Int64Attribute("reqlen", int64(req.RequestLength)),
|
||||
)
|
||||
|
||||
reqlen := req.RequestLength
|
||||
if reqlen > BlockSyncMaxRequestLength {
|
||||
log.Warnw("limiting blocksync request length", "orig", req.RequestLength, "peer", p)
|
||||
reqlen = BlockSyncMaxRequestLength
|
||||
}
|
||||
|
||||
chain, err := collectChainSegment(bss.cs, types.NewTipSetKey(req.Start...), reqlen, opts)
|
||||
if err != nil {
|
||||
log.Warn("encountered error while responding to block sync request: ", err)
|
||||
return &BlockSyncResponse{
|
||||
Status: StatusInternalError,
|
||||
Message: err.Error(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
status := StatusOK
|
||||
if reqlen < req.RequestLength {
|
||||
status = StatusPartial
|
||||
}
|
||||
|
||||
return &BlockSyncResponse{
|
||||
Chain: chain,
|
||||
Status: status,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func collectChainSegment(cs *store.ChainStore, start types.TipSetKey, length uint64, opts *BSOptions) ([]*BSTipSet, error) {
|
||||
var bstips []*BSTipSet
|
||||
cur := start
|
||||
for {
|
||||
var bst BSTipSet
|
||||
ts, err := cs.LoadTipSet(cur)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed loading tipset %s: %w", cur, err)
|
||||
}
|
||||
|
||||
if opts.IncludeMessages {
|
||||
bmsgs, bmincl, smsgs, smincl, err := gatherMessages(cs, ts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("gather messages failed: %w", err)
|
||||
}
|
||||
|
||||
bst.BlsMessages = bmsgs
|
||||
bst.BlsMsgIncludes = bmincl
|
||||
bst.SecpkMessages = smsgs
|
||||
bst.SecpkMsgIncludes = smincl
|
||||
}
|
||||
|
||||
if opts.IncludeBlocks {
|
||||
bst.Blocks = ts.Blocks()
|
||||
}
|
||||
|
||||
bstips = append(bstips, &bst)
|
||||
|
||||
if uint64(len(bstips)) >= length || ts.Height() == 0 {
|
||||
return bstips, nil
|
||||
}
|
||||
|
||||
cur = ts.Parents()
|
||||
}
|
||||
}
|
||||
|
||||
func gatherMessages(cs *store.ChainStore, ts *types.TipSet) ([]*types.Message, [][]uint64, []*types.SignedMessage, [][]uint64, error) {
|
||||
blsmsgmap := make(map[cid.Cid]uint64)
|
||||
secpkmsgmap := make(map[cid.Cid]uint64)
|
||||
var secpkmsgs []*types.SignedMessage
|
||||
var blsmsgs []*types.Message
|
||||
var secpkincl, blsincl [][]uint64
|
||||
|
||||
for _, b := range ts.Blocks() {
|
||||
bmsgs, smsgs, err := cs.MessagesForBlock(b)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
|
||||
bmi := make([]uint64, 0, len(bmsgs))
|
||||
for _, m := range bmsgs {
|
||||
i, ok := blsmsgmap[m.Cid()]
|
||||
if !ok {
|
||||
i = uint64(len(blsmsgs))
|
||||
blsmsgs = append(blsmsgs, m)
|
||||
blsmsgmap[m.Cid()] = i
|
||||
}
|
||||
|
||||
bmi = append(bmi, i)
|
||||
}
|
||||
blsincl = append(blsincl, bmi)
|
||||
|
||||
smi := make([]uint64, 0, len(smsgs))
|
||||
for _, m := range smsgs {
|
||||
i, ok := secpkmsgmap[m.Cid()]
|
||||
if !ok {
|
||||
i = uint64(len(secpkmsgs))
|
||||
secpkmsgs = append(secpkmsgs, m)
|
||||
secpkmsgmap[m.Cid()] = i
|
||||
}
|
||||
|
||||
smi = append(smi, i)
|
||||
}
|
||||
secpkincl = append(secpkincl, smi)
|
||||
}
|
||||
|
||||
return blsmsgs, blsincl, secpkmsgs, secpkincl, nil
|
||||
}
|
||||
|
||||
func bstsToFullTipSet(bts *BSTipSet) (*store.FullTipSet, error) {
|
||||
fts := &store.FullTipSet{}
|
||||
for i, b := range bts.Blocks {
|
||||
fb := &types.FullBlock{
|
||||
Header: b,
|
||||
}
|
||||
for _, mi := range bts.BlsMsgIncludes[i] {
|
||||
fb.BlsMessages = append(fb.BlsMessages, bts.BlsMessages[mi])
|
||||
}
|
||||
for _, mi := range bts.SecpkMsgIncludes[i] {
|
||||
fb.SecpkMessages = append(fb.SecpkMessages, bts.SecpkMessages[mi])
|
||||
}
|
||||
|
||||
fts.Blocks = append(fts.Blocks, fb)
|
||||
}
|
||||
|
||||
return fts, nil
|
||||
}
|
||||
@@ -1,602 +0,0 @@
|
||||
package blocksync
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
blocks "github.com/ipfs/go-block-format"
|
||||
bserv "github.com/ipfs/go-blockservice"
|
||||
"github.com/ipfs/go-cid"
|
||||
graphsync "github.com/ipfs/go-graphsync"
|
||||
gsnet "github.com/ipfs/go-graphsync/network"
|
||||
host "github.com/libp2p/go-libp2p-core/host"
|
||||
inet "github.com/libp2p/go-libp2p-core/network"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
"go.opencensus.io/trace"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
cborutil "github.com/filecoin-project/go-cbor-util"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
incrt "github.com/filecoin-project/lotus/lib/increadtimeout"
|
||||
"github.com/filecoin-project/lotus/lib/peermgr"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
)
|
||||
|
||||
type BlockSync struct {
|
||||
bserv bserv.BlockService
|
||||
gsync graphsync.GraphExchange
|
||||
host host.Host
|
||||
|
||||
syncPeers *bsPeerTracker
|
||||
peerMgr *peermgr.PeerMgr
|
||||
}
|
||||
|
||||
func NewBlockSyncClient(bserv dtypes.ChainBlockService, h host.Host, pmgr peermgr.MaybePeerMgr, gs dtypes.Graphsync) *BlockSync {
|
||||
return &BlockSync{
|
||||
bserv: bserv,
|
||||
host: h,
|
||||
syncPeers: newPeerTracker(pmgr.Mgr),
|
||||
peerMgr: pmgr.Mgr,
|
||||
gsync: gs,
|
||||
}
|
||||
}
|
||||
|
||||
func (bs *BlockSync) processStatus(req *BlockSyncRequest, res *BlockSyncResponse) error {
|
||||
switch res.Status {
|
||||
case StatusPartial: // Partial Response
|
||||
return xerrors.Errorf("not handling partial blocksync responses yet")
|
||||
case StatusNotFound: // req.Start not found
|
||||
return xerrors.Errorf("not found")
|
||||
case StatusGoAway: // Go Away
|
||||
return xerrors.Errorf("not handling 'go away' blocksync responses yet")
|
||||
case StatusInternalError: // Internal Error
|
||||
return xerrors.Errorf("block sync peer errored: %s", res.Message)
|
||||
case StatusBadRequest:
|
||||
return xerrors.Errorf("block sync request invalid: %s", res.Message)
|
||||
default:
|
||||
return xerrors.Errorf("unrecognized response code: %d", res.Status)
|
||||
}
|
||||
}
|
||||
|
||||
// GetBlocks fetches count blocks from the network, from the provided tipset
|
||||
// *backwards*, returning as many tipsets as count.
|
||||
//
|
||||
// {hint/usage}: This is used by the Syncer during normal chain syncing and when
|
||||
// resolving forks.
|
||||
func (bs *BlockSync) GetBlocks(ctx context.Context, tsk types.TipSetKey, count int) ([]*types.TipSet, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "bsync.GetBlocks")
|
||||
defer span.End()
|
||||
if span.IsRecordingEvents() {
|
||||
span.AddAttributes(
|
||||
trace.StringAttribute("tipset", fmt.Sprint(tsk.Cids())),
|
||||
trace.Int64Attribute("count", int64(count)),
|
||||
)
|
||||
}
|
||||
|
||||
req := &BlockSyncRequest{
|
||||
Start: tsk.Cids(),
|
||||
RequestLength: uint64(count),
|
||||
Options: BSOptBlocks,
|
||||
}
|
||||
|
||||
// this peerset is sorted by latency and failure counting.
|
||||
peers := bs.getPeers()
|
||||
|
||||
// randomize the first few peers so we don't always pick the same peer
|
||||
shufflePrefix(peers)
|
||||
|
||||
start := time.Now()
|
||||
var oerr error
|
||||
|
||||
for _, p := range peers {
|
||||
// TODO: doing this synchronously isnt great, but fetching in parallel
|
||||
// may not be a good idea either. think about this more
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, xerrors.Errorf("blocksync getblocks failed: %w", ctx.Err())
|
||||
default:
|
||||
}
|
||||
|
||||
res, err := bs.sendRequestToPeer(ctx, p, req)
|
||||
if err != nil {
|
||||
oerr = err
|
||||
if !xerrors.Is(err, inet.ErrNoConn) {
|
||||
log.Warnf("BlockSync request failed for peer %s: %s", p.String(), err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if res.Status == StatusOK || res.Status == StatusPartial {
|
||||
resp, err := bs.processBlocksResponse(req, res)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("success response from peer failed to process: %w", err)
|
||||
}
|
||||
bs.syncPeers.logGlobalSuccess(time.Since(start))
|
||||
bs.host.ConnManager().TagPeer(p, "bsync", 25)
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
oerr = bs.processStatus(req, res)
|
||||
if oerr != nil {
|
||||
log.Warnf("BlockSync peer %s response was an error: %s", p.String(), oerr)
|
||||
}
|
||||
}
|
||||
return nil, xerrors.Errorf("GetBlocks failed with all peers: %w", oerr)
|
||||
}
|
||||
|
||||
func (bs *BlockSync) GetFullTipSet(ctx context.Context, p peer.ID, tsk types.TipSetKey) (*store.FullTipSet, error) {
|
||||
// TODO: round robin through these peers on error
|
||||
|
||||
req := &BlockSyncRequest{
|
||||
Start: tsk.Cids(),
|
||||
RequestLength: 1,
|
||||
Options: BSOptBlocks | BSOptMessages,
|
||||
}
|
||||
|
||||
res, err := bs.sendRequestToPeer(ctx, p, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch res.Status {
|
||||
case 0: // Success
|
||||
if len(res.Chain) == 0 {
|
||||
return nil, fmt.Errorf("got zero length chain response")
|
||||
}
|
||||
bts := res.Chain[0]
|
||||
|
||||
return bstsToFullTipSet(bts)
|
||||
case 101: // Partial Response
|
||||
return nil, xerrors.Errorf("partial responses are not handled for single tipset fetching")
|
||||
case 201: // req.Start not found
|
||||
return nil, fmt.Errorf("not found")
|
||||
case 202: // Go Away
|
||||
return nil, xerrors.Errorf("received 'go away' response peer")
|
||||
case 203: // Internal Error
|
||||
return nil, fmt.Errorf("block sync peer errored: %q", res.Message)
|
||||
case 204: // Invalid Request
|
||||
return nil, fmt.Errorf("block sync request invalid: %q", res.Message)
|
||||
default:
|
||||
return nil, fmt.Errorf("unrecognized response code")
|
||||
}
|
||||
}
|
||||
|
||||
func shufflePrefix(peers []peer.ID) {
|
||||
pref := 5
|
||||
if len(peers) < pref {
|
||||
pref = len(peers)
|
||||
}
|
||||
|
||||
buf := make([]peer.ID, pref)
|
||||
perm := rand.Perm(pref)
|
||||
for i, v := range perm {
|
||||
buf[i] = peers[v]
|
||||
}
|
||||
|
||||
copy(peers, buf)
|
||||
}
|
||||
|
||||
func (bs *BlockSync) GetChainMessages(ctx context.Context, h *types.TipSet, count uint64) ([]*BSTipSet, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "GetChainMessages")
|
||||
defer span.End()
|
||||
|
||||
peers := bs.getPeers()
|
||||
// randomize the first few peers so we don't always pick the same peer
|
||||
shufflePrefix(peers)
|
||||
|
||||
req := &BlockSyncRequest{
|
||||
Start: h.Cids(),
|
||||
RequestLength: count,
|
||||
Options: BSOptMessages,
|
||||
}
|
||||
|
||||
var err error
|
||||
start := time.Now()
|
||||
|
||||
for _, p := range peers {
|
||||
res, rerr := bs.sendRequestToPeer(ctx, p, req)
|
||||
if rerr != nil {
|
||||
err = rerr
|
||||
log.Warnf("BlockSync request failed for peer %s: %s", p.String(), err)
|
||||
continue
|
||||
}
|
||||
|
||||
if res.Status == StatusOK {
|
||||
bs.syncPeers.logGlobalSuccess(time.Since(start))
|
||||
return res.Chain, nil
|
||||
}
|
||||
|
||||
if res.Status == StatusPartial {
|
||||
// TODO: track partial response sizes to ensure we don't overrequest too often
|
||||
return res.Chain, nil
|
||||
}
|
||||
|
||||
err = bs.processStatus(req, res)
|
||||
if err != nil {
|
||||
log.Warnf("BlockSync peer %s response was an error: %s", p.String(), err)
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
return nil, xerrors.Errorf("GetChainMessages failed, no peers connected")
|
||||
}
|
||||
|
||||
// TODO: What if we have no peers (and err is nil)?
|
||||
return nil, xerrors.Errorf("GetChainMessages failed with all peers(%d): %w", len(peers), err)
|
||||
}
|
||||
|
||||
func (bs *BlockSync) sendRequestToPeer(ctx context.Context, p peer.ID, req *BlockSyncRequest) (_ *BlockSyncResponse, err error) {
|
||||
ctx, span := trace.StartSpan(ctx, "sendRequestToPeer")
|
||||
defer span.End()
|
||||
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if span.IsRecordingEvents() {
|
||||
span.SetStatus(trace.Status{
|
||||
Code: 5,
|
||||
Message: err.Error(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
if span.IsRecordingEvents() {
|
||||
span.AddAttributes(
|
||||
trace.StringAttribute("peer", p.Pretty()),
|
||||
)
|
||||
}
|
||||
|
||||
gsproto := string(gsnet.ProtocolGraphsync)
|
||||
supp, err := bs.host.Peerstore().SupportsProtocols(p, BlockSyncProtocolID, gsproto)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to get protocols for peer: %w", err)
|
||||
}
|
||||
|
||||
if len(supp) == 0 {
|
||||
return nil, xerrors.Errorf("peer %s supports no known sync protocols", p)
|
||||
}
|
||||
|
||||
switch supp[0] {
|
||||
case BlockSyncProtocolID:
|
||||
res, err := bs.fetchBlocksBlockSync(ctx, p, req)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("blocksync req failed: %w", err)
|
||||
}
|
||||
return res, nil
|
||||
case gsproto:
|
||||
res, err := bs.fetchBlocksGraphSync(ctx, p, req)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("graphsync req failed: %w", err)
|
||||
}
|
||||
return res, nil
|
||||
default:
|
||||
return nil, xerrors.Errorf("peerstore somehow returned unexpected protocols: %v", supp)
|
||||
}
|
||||
|
||||
}
|
||||
func (bs *BlockSync) fetchBlocksBlockSync(ctx context.Context, p peer.ID, req *BlockSyncRequest) (*BlockSyncResponse, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "blockSyncFetch")
|
||||
defer span.End()
|
||||
|
||||
start := time.Now()
|
||||
s, err := bs.host.NewStream(inet.WithNoDial(ctx, "should already have connection"), p, BlockSyncProtocolID)
|
||||
if err != nil {
|
||||
bs.RemovePeer(p)
|
||||
return nil, xerrors.Errorf("failed to open stream to peer: %w", err)
|
||||
}
|
||||
_ = s.SetWriteDeadline(time.Now().Add(5 * time.Second))
|
||||
|
||||
if err := cborutil.WriteCborRPC(s, req); err != nil {
|
||||
_ = s.SetWriteDeadline(time.Time{})
|
||||
bs.syncPeers.logFailure(p, time.Since(start))
|
||||
return nil, err
|
||||
}
|
||||
_ = s.SetWriteDeadline(time.Time{})
|
||||
|
||||
var res BlockSyncResponse
|
||||
r := incrt.New(s, 50<<10, 5*time.Second)
|
||||
if err := cborutil.ReadCborRPC(bufio.NewReader(r), &res); err != nil {
|
||||
bs.syncPeers.logFailure(p, time.Since(start))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if span.IsRecordingEvents() {
|
||||
span.AddAttributes(
|
||||
trace.Int64Attribute("resp_status", int64(res.Status)),
|
||||
trace.StringAttribute("msg", res.Message),
|
||||
trace.Int64Attribute("chain_len", int64(len(res.Chain))),
|
||||
)
|
||||
}
|
||||
|
||||
bs.syncPeers.logSuccess(p, time.Since(start))
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func (bs *BlockSync) processBlocksResponse(req *BlockSyncRequest, res *BlockSyncResponse) ([]*types.TipSet, error) {
|
||||
if len(res.Chain) == 0 {
|
||||
return nil, xerrors.Errorf("got no blocks in successful blocksync response")
|
||||
}
|
||||
|
||||
cur, err := types.NewTipSet(res.Chain[0].Blocks)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out := []*types.TipSet{cur}
|
||||
for bi := 1; bi < len(res.Chain); bi++ {
|
||||
next := res.Chain[bi].Blocks
|
||||
nts, err := types.NewTipSet(next)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !types.CidArrsEqual(cur.Parents().Cids(), nts.Cids()) {
|
||||
return nil, fmt.Errorf("parents of tipset[%d] were not tipset[%d]", bi-1, bi)
|
||||
}
|
||||
|
||||
out = append(out, nts)
|
||||
cur = nts
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (bs *BlockSync) GetBlock(ctx context.Context, c cid.Cid) (*types.BlockHeader, error) {
|
||||
sb, err := bs.bserv.GetBlock(ctx, c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return types.DecodeBlock(sb.RawData())
|
||||
}
|
||||
|
||||
func (bs *BlockSync) AddPeer(p peer.ID) {
|
||||
bs.syncPeers.addPeer(p)
|
||||
}
|
||||
|
||||
func (bs *BlockSync) RemovePeer(p peer.ID) {
|
||||
bs.syncPeers.removePeer(p)
|
||||
}
|
||||
|
||||
// getPeers returns a preference-sorted set of peers to query.
|
||||
func (bs *BlockSync) getPeers() []peer.ID {
|
||||
return bs.syncPeers.prefSortedPeers()
|
||||
}
|
||||
|
||||
func (bs *BlockSync) FetchMessagesByCids(ctx context.Context, cids []cid.Cid) ([]*types.Message, error) {
|
||||
out := make([]*types.Message, len(cids))
|
||||
|
||||
err := bs.fetchCids(ctx, cids, func(i int, b blocks.Block) error {
|
||||
msg, err := types.DecodeMessage(b.RawData())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if out[i] != nil {
|
||||
return fmt.Errorf("received duplicate message")
|
||||
}
|
||||
|
||||
out[i] = msg
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (bs *BlockSync) FetchSignedMessagesByCids(ctx context.Context, cids []cid.Cid) ([]*types.SignedMessage, error) {
|
||||
out := make([]*types.SignedMessage, len(cids))
|
||||
|
||||
err := bs.fetchCids(ctx, cids, func(i int, b blocks.Block) error {
|
||||
smsg, err := types.DecodeSignedMessage(b.RawData())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if out[i] != nil {
|
||||
return fmt.Errorf("received duplicate message")
|
||||
}
|
||||
|
||||
out[i] = smsg
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (bs *BlockSync) fetchCids(ctx context.Context, cids []cid.Cid, cb func(int, blocks.Block) error) error {
|
||||
resp := bs.bserv.GetBlocks(context.TODO(), cids)
|
||||
|
||||
m := make(map[cid.Cid]int)
|
||||
for i, c := range cids {
|
||||
m[c] = i
|
||||
}
|
||||
|
||||
for i := 0; i < len(cids); i++ {
|
||||
select {
|
||||
case v, ok := <-resp:
|
||||
if !ok {
|
||||
if i == len(cids)-1 {
|
||||
break
|
||||
}
|
||||
|
||||
return fmt.Errorf("failed to fetch all messages")
|
||||
}
|
||||
|
||||
ix, ok := m[v.Cid()]
|
||||
if !ok {
|
||||
return fmt.Errorf("received message we didnt ask for")
|
||||
}
|
||||
|
||||
if err := cb(ix, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type peerStats struct {
|
||||
successes int
|
||||
failures int
|
||||
firstSeen time.Time
|
||||
averageTime time.Duration
|
||||
}
|
||||
|
||||
type bsPeerTracker struct {
|
||||
lk sync.Mutex
|
||||
|
||||
peers map[peer.ID]*peerStats
|
||||
avgGlobalTime time.Duration
|
||||
|
||||
pmgr *peermgr.PeerMgr
|
||||
}
|
||||
|
||||
func newPeerTracker(pmgr *peermgr.PeerMgr) *bsPeerTracker {
|
||||
return &bsPeerTracker{
|
||||
peers: make(map[peer.ID]*peerStats),
|
||||
pmgr: pmgr,
|
||||
}
|
||||
}
|
||||
|
||||
func (bpt *bsPeerTracker) addPeer(p peer.ID) {
|
||||
bpt.lk.Lock()
|
||||
defer bpt.lk.Unlock()
|
||||
if _, ok := bpt.peers[p]; ok {
|
||||
return
|
||||
}
|
||||
bpt.peers[p] = &peerStats{
|
||||
firstSeen: time.Now(),
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const (
|
||||
// newPeerMul is how much better than average is the new peer assumed to be
|
||||
// less than one to encourouge trying new peers
|
||||
newPeerMul = 0.9
|
||||
)
|
||||
|
||||
func (bpt *bsPeerTracker) prefSortedPeers() []peer.ID {
|
||||
// TODO: this could probably be cached, but as long as its not too many peers, fine for now
|
||||
bpt.lk.Lock()
|
||||
defer bpt.lk.Unlock()
|
||||
out := make([]peer.ID, 0, len(bpt.peers))
|
||||
for p := range bpt.peers {
|
||||
out = append(out, p)
|
||||
}
|
||||
|
||||
// sort by 'expected cost' of requesting data from that peer
|
||||
// additionally handle edge cases where not enough data is available
|
||||
sort.Slice(out, func(i, j int) bool {
|
||||
pi := bpt.peers[out[i]]
|
||||
pj := bpt.peers[out[j]]
|
||||
|
||||
var costI, costJ float64
|
||||
|
||||
getPeerInitLat := func(p peer.ID) float64 {
|
||||
var res float64
|
||||
if bpt.pmgr != nil {
|
||||
if lat, ok := bpt.pmgr.GetPeerLatency(p); ok {
|
||||
res = float64(lat)
|
||||
}
|
||||
}
|
||||
if res == 0 {
|
||||
res = float64(bpt.avgGlobalTime)
|
||||
}
|
||||
return res * newPeerMul
|
||||
}
|
||||
|
||||
if pi.successes+pi.failures > 0 {
|
||||
failRateI := float64(pi.failures) / float64(pi.failures+pi.successes)
|
||||
costI = float64(pi.averageTime) + failRateI*float64(bpt.avgGlobalTime)
|
||||
} else {
|
||||
costI = getPeerInitLat(out[i])
|
||||
}
|
||||
|
||||
if pj.successes+pj.failures > 0 {
|
||||
failRateJ := float64(pj.failures) / float64(pj.failures+pj.successes)
|
||||
costJ = float64(pj.averageTime) + failRateJ*float64(bpt.avgGlobalTime)
|
||||
} else {
|
||||
costJ = getPeerInitLat(out[j])
|
||||
}
|
||||
|
||||
return costI < costJ
|
||||
})
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
const (
|
||||
// xInvAlpha = (N+1)/2
|
||||
|
||||
localInvAlpha = 5 // 86% of the value is the last 9
|
||||
globalInvAlpha = 20 // 86% of the value is the last 39
|
||||
)
|
||||
|
||||
func (bpt *bsPeerTracker) logGlobalSuccess(dur time.Duration) {
|
||||
bpt.lk.Lock()
|
||||
defer bpt.lk.Unlock()
|
||||
|
||||
if bpt.avgGlobalTime == 0 {
|
||||
bpt.avgGlobalTime = dur
|
||||
return
|
||||
}
|
||||
delta := (dur - bpt.avgGlobalTime) / globalInvAlpha
|
||||
bpt.avgGlobalTime += delta
|
||||
}
|
||||
|
||||
func logTime(pi *peerStats, dur time.Duration) {
|
||||
if pi.averageTime == 0 {
|
||||
pi.averageTime = dur
|
||||
return
|
||||
}
|
||||
delta := (dur - pi.averageTime) / localInvAlpha
|
||||
pi.averageTime += delta
|
||||
|
||||
}
|
||||
|
||||
func (bpt *bsPeerTracker) logSuccess(p peer.ID, dur time.Duration) {
|
||||
bpt.lk.Lock()
|
||||
defer bpt.lk.Unlock()
|
||||
|
||||
var pi *peerStats
|
||||
var ok bool
|
||||
if pi, ok = bpt.peers[p]; !ok {
|
||||
log.Warnw("log success called on peer not in tracker", "peerid", p.String())
|
||||
return
|
||||
}
|
||||
|
||||
pi.successes++
|
||||
logTime(pi, dur)
|
||||
}
|
||||
|
||||
func (bpt *bsPeerTracker) logFailure(p peer.ID, dur time.Duration) {
|
||||
bpt.lk.Lock()
|
||||
defer bpt.lk.Unlock()
|
||||
|
||||
var pi *peerStats
|
||||
var ok bool
|
||||
if pi, ok = bpt.peers[p]; !ok {
|
||||
log.Warn("log failure called on peer not in tracker", "peerid", p.String())
|
||||
return
|
||||
}
|
||||
|
||||
pi.failures++
|
||||
logTime(pi, dur)
|
||||
}
|
||||
|
||||
func (bpt *bsPeerTracker) removePeer(p peer.ID) {
|
||||
bpt.lk.Lock()
|
||||
defer bpt.lk.Unlock()
|
||||
delete(bpt.peers, p)
|
||||
}
|
||||
@@ -1,151 +0,0 @@
|
||||
package blocksync
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-datastore"
|
||||
"github.com/ipfs/go-graphsync"
|
||||
"github.com/ipld/go-ipld-prime"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
store "github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
|
||||
cidlink "github.com/ipld/go-ipld-prime/linking/cid"
|
||||
basicnode "github.com/ipld/go-ipld-prime/node/basic"
|
||||
ipldselector "github.com/ipld/go-ipld-prime/traversal/selector"
|
||||
selectorbuilder "github.com/ipld/go-ipld-prime/traversal/selector/builder"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
// AMT selector recursion. An AMT has arity of 8 so this gives allows
|
||||
// us to retrieve trees with 8^10 (1,073,741,824) elements.
|
||||
amtRecursionDepth = uint32(10)
|
||||
|
||||
// some constants for looking up tuple encoded struct fields
|
||||
// field index of Parents field in a block header
|
||||
blockIndexParentsField = 5
|
||||
|
||||
// field index of Messages field in a block header
|
||||
blockIndexMessagesField = 10
|
||||
|
||||
// field index of AMT node in AMT head
|
||||
amtHeadNodeFieldIndex = 2
|
||||
|
||||
// field index of links array AMT node
|
||||
amtNodeLinksFieldIndex = 1
|
||||
|
||||
// field index of values array AMT node
|
||||
amtNodeValuesFieldIndex = 2
|
||||
|
||||
// maximum depth per traversal
|
||||
maxRequestLength = 50
|
||||
)
|
||||
|
||||
var amtSelector selectorbuilder.SelectorSpec
|
||||
|
||||
func init() {
|
||||
// builer for selectors
|
||||
ssb := selectorbuilder.NewSelectorSpecBuilder(basicnode.Style.Any)
|
||||
// amt selector -- needed to selector through a messages AMT
|
||||
amtSelector = ssb.ExploreIndex(amtHeadNodeFieldIndex,
|
||||
ssb.ExploreRecursive(ipldselector.RecursionLimitDepth(int(amtRecursionDepth)),
|
||||
ssb.ExploreUnion(
|
||||
ssb.ExploreIndex(amtNodeLinksFieldIndex,
|
||||
ssb.ExploreAll(ssb.ExploreRecursiveEdge())),
|
||||
ssb.ExploreIndex(amtNodeValuesFieldIndex,
|
||||
ssb.ExploreAll(ssb.Matcher())))))
|
||||
}
|
||||
|
||||
func selectorForRequest(req *BlockSyncRequest) ipld.Node {
|
||||
// builer for selectors
|
||||
ssb := selectorbuilder.NewSelectorSpecBuilder(basicnode.Style.Any)
|
||||
|
||||
bso := ParseBSOptions(req.Options)
|
||||
if bso.IncludeMessages {
|
||||
return ssb.ExploreRecursive(ipldselector.RecursionLimitDepth(int(req.RequestLength)),
|
||||
ssb.ExploreIndex(blockIndexParentsField,
|
||||
ssb.ExploreUnion(
|
||||
ssb.ExploreAll(
|
||||
ssb.ExploreIndex(blockIndexMessagesField,
|
||||
ssb.ExploreRange(0, 2, amtSelector),
|
||||
)),
|
||||
ssb.ExploreIndex(0, ssb.ExploreRecursiveEdge()),
|
||||
))).Node()
|
||||
}
|
||||
return ssb.ExploreRecursive(ipldselector.RecursionLimitDepth(int(req.RequestLength)), ssb.ExploreIndex(blockIndexParentsField,
|
||||
ssb.ExploreUnion(
|
||||
ssb.ExploreAll(
|
||||
ssb.Matcher(),
|
||||
),
|
||||
ssb.ExploreIndex(0, ssb.ExploreRecursiveEdge()),
|
||||
))).Node()
|
||||
}
|
||||
|
||||
func firstTipsetSelector(req *BlockSyncRequest) ipld.Node {
|
||||
// builer for selectors
|
||||
ssb := selectorbuilder.NewSelectorSpecBuilder(basicnode.Style.Any)
|
||||
|
||||
bso := ParseBSOptions(req.Options)
|
||||
if bso.IncludeMessages {
|
||||
return ssb.ExploreIndex(blockIndexMessagesField,
|
||||
ssb.ExploreRange(0, 2, amtSelector),
|
||||
).Node()
|
||||
}
|
||||
return ssb.Matcher().Node()
|
||||
|
||||
}
|
||||
|
||||
func (bs *BlockSync) executeGsyncSelector(ctx context.Context, p peer.ID, root cid.Cid, sel ipld.Node) error {
|
||||
extension := graphsync.ExtensionData{
|
||||
Name: "chainsync",
|
||||
Data: nil,
|
||||
}
|
||||
_, errs := bs.gsync.Request(ctx, p, cidlink.Link{Cid: root}, sel, extension)
|
||||
|
||||
for err := range errs {
|
||||
return xerrors.Errorf("failed to complete graphsync request: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Fallback for interacting with other non-lotus nodes
|
||||
func (bs *BlockSync) fetchBlocksGraphSync(ctx context.Context, p peer.ID, req *BlockSyncRequest) (*BlockSyncResponse, error) {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
immediateTsSelector := firstTipsetSelector(req)
|
||||
|
||||
// Do this because we can only request one root at a time
|
||||
for _, r := range req.Start {
|
||||
if err := bs.executeGsyncSelector(ctx, p, r, immediateTsSelector); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if req.RequestLength > maxRequestLength {
|
||||
req.RequestLength = maxRequestLength
|
||||
}
|
||||
|
||||
sel := selectorForRequest(req)
|
||||
|
||||
// execute the selector forreal
|
||||
if err := bs.executeGsyncSelector(ctx, p, req.Start[0], sel); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Now pull the data we fetched out of the chainstore (where it should now be persisted)
|
||||
tempcs := store.NewChainStore(bs.bserv.Blockstore(), datastore.NewMapDatastore(), nil)
|
||||
|
||||
opts := ParseBSOptions(req.Options)
|
||||
tsk := types.NewTipSetKey(req.Start...)
|
||||
chain, err := collectChainSegment(tempcs, tsk, req.RequestLength, opts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load chain data from chainstore after successful graphsync response (start = %v): %w", req.Start, err)
|
||||
}
|
||||
|
||||
return &BlockSyncResponse{Chain: chain}, nil
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package chain
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
"github.com/ipfs/go-datastore"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
var CheckpointKey = datastore.NewKey("/chain/checks")
|
||||
|
||||
func loadCheckpoint(ds dtypes.MetadataDS) (types.TipSetKey, error) {
|
||||
haveChks, err := ds.Has(CheckpointKey)
|
||||
if err != nil {
|
||||
return types.EmptyTSK, err
|
||||
}
|
||||
|
||||
if !haveChks {
|
||||
return types.EmptyTSK, nil
|
||||
}
|
||||
|
||||
tskBytes, err := ds.Get(CheckpointKey)
|
||||
if err != nil {
|
||||
return types.EmptyTSK, err
|
||||
}
|
||||
|
||||
var tsk types.TipSetKey
|
||||
err = json.Unmarshal(tskBytes, &tsk)
|
||||
if err != nil {
|
||||
return types.EmptyTSK, err
|
||||
}
|
||||
|
||||
return tsk, err
|
||||
}
|
||||
|
||||
func (syncer *Syncer) SetCheckpoint(tsk types.TipSetKey) error {
|
||||
if tsk == types.EmptyTSK {
|
||||
return xerrors.Errorf("called with empty tsk")
|
||||
}
|
||||
|
||||
syncer.checkptLk.Lock()
|
||||
defer syncer.checkptLk.Unlock()
|
||||
|
||||
ts, err := syncer.ChainStore().LoadTipSet(tsk)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("cannot find tipset: %w", err)
|
||||
}
|
||||
|
||||
hts := syncer.ChainStore().GetHeaviestTipSet()
|
||||
anc, err := syncer.ChainStore().IsAncestorOf(ts, hts)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("cannot determine whether checkpoint tipset is in main-chain: %w", err)
|
||||
}
|
||||
|
||||
if !hts.Equals(ts) && !anc {
|
||||
return xerrors.Errorf("cannot mark tipset as checkpoint, since it isn't in the main-chain: %w", err)
|
||||
}
|
||||
|
||||
tskBytes, err := json.Marshal(tsk)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = syncer.ds.Put(CheckpointKey, tskBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
syncer.checkpt = tsk
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (syncer *Syncer) GetCheckpoint() types.TipSetKey {
|
||||
syncer.checkptLk.Lock()
|
||||
defer syncer.checkptLk.Unlock()
|
||||
return syncer.checkpt
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/ipfs/go-cid"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"golang.org/x/xerrors"
|
||||
@@ -35,6 +35,7 @@ type eventAPI interface {
|
||||
ChainNotify(context.Context) (<-chan []*api.HeadChange, error)
|
||||
ChainGetBlockMessages(context.Context, cid.Cid) (*api.BlockMessages, error)
|
||||
ChainGetTipSetByHeight(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error)
|
||||
ChainHead(context.Context) (*types.TipSet, error)
|
||||
StateGetReceipt(context.Context, cid.Cid, types.TipSetKey) (*types.MessageReceipt, error)
|
||||
ChainGetTipSet(context.Context, types.TipSetKey) (*types.TipSet, error)
|
||||
|
||||
@@ -57,7 +58,7 @@ type Events struct {
|
||||
func NewEvents(ctx context.Context, api eventAPI) *Events {
|
||||
gcConfidence := 2 * build.ForkLengthThreshold
|
||||
|
||||
tsc := newTSCache(gcConfidence, api.ChainGetTipSetByHeight)
|
||||
tsc := newTSCache(gcConfidence, api)
|
||||
|
||||
e := &Events{
|
||||
api: api,
|
||||
@@ -99,7 +100,7 @@ func (e *Events) listenHeadChanges(ctx context.Context) {
|
||||
log.Warnf("not restarting listenHeadChanges: context error: %s", ctx.Err())
|
||||
return
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
build.Clock.Sleep(time.Second)
|
||||
log.Info("restarting listenHeadChanges")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"math"
|
||||
"sync"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/ipfs/go-cid"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
@@ -307,7 +307,10 @@ func (e *hcEvents) onHeadChanged(check CheckFunc, hnd EventHandler, rev RevertHa
|
||||
defer e.lk.Unlock()
|
||||
|
||||
// Check if the event has already occurred
|
||||
ts := e.tsc.best()
|
||||
ts, err := e.tsc.best()
|
||||
if err != nil {
|
||||
return 0, xerrors.Errorf("error getting best tipset: %w", err)
|
||||
}
|
||||
done, more, err := check(ts)
|
||||
if err != nil {
|
||||
return 0, xerrors.Errorf("called check error (h: %d): %w", ts.Height(), err)
|
||||
@@ -485,13 +488,15 @@ func (me *messageEvents) checkNewCalls(ts *types.TipSet) (map[triggerID]eventDat
|
||||
|
||||
for tid, matchFns := range me.matchers {
|
||||
var matched bool
|
||||
var once bool
|
||||
for _, matchFn := range matchFns {
|
||||
ok, err := matchFn(msg)
|
||||
matchOne, ok, err := matchFn(msg)
|
||||
if err != nil {
|
||||
log.Errorf("event matcher failed: %s", err)
|
||||
continue
|
||||
}
|
||||
matched = ok
|
||||
once = matchOne
|
||||
|
||||
if matched {
|
||||
break
|
||||
@@ -500,7 +505,9 @@ func (me *messageEvents) checkNewCalls(ts *types.TipSet) (map[triggerID]eventDat
|
||||
|
||||
if matched {
|
||||
res[tid] = msg
|
||||
break
|
||||
if once {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -548,7 +555,7 @@ func (me *messageEvents) messagesForTs(ts *types.TipSet, consume func(*types.Mes
|
||||
// `curH`-`ts.Height` = `confidence`
|
||||
type MsgHandler func(msg *types.Message, rec *types.MessageReceipt, ts *types.TipSet, curH abi.ChainEpoch) (more bool, err error)
|
||||
|
||||
type MsgMatchFunc func(msg *types.Message) (bool, error)
|
||||
type MsgMatchFunc func(msg *types.Message) (matchOnce bool, matched bool, err error)
|
||||
|
||||
// Called registers a callback which is triggered when a specified method is
|
||||
// called on an actor, or a timeout is reached.
|
||||
|
||||
@@ -4,8 +4,9 @@ import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"go.opencensus.io/trace"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
@@ -152,8 +153,12 @@ func (e *heightEvents) ChainAt(hnd HeightHandler, rev RevertHandler, confidence
|
||||
|
||||
e.lk.Lock() // Tricky locking, check your locks if you modify this function!
|
||||
|
||||
bestH := e.tsc.best().Height()
|
||||
best, err := e.tsc.best()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error getting best tipset: %w", err)
|
||||
}
|
||||
|
||||
bestH := best.Height()
|
||||
if bestH >= h+abi.ChainEpoch(confidence) {
|
||||
ts, err := e.tsc.getNonNull(h)
|
||||
if err != nil {
|
||||
@@ -172,7 +177,11 @@ func (e *heightEvents) ChainAt(hnd HeightHandler, rev RevertHandler, confidence
|
||||
}
|
||||
|
||||
e.lk.Lock()
|
||||
bestH = e.tsc.best().Height()
|
||||
best, err = e.tsc.best()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error getting best tipset: %w", err)
|
||||
}
|
||||
bestH = best.Height()
|
||||
}
|
||||
|
||||
defer e.lk.Unlock()
|
||||
|
||||
@@ -11,8 +11,8 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
@@ -46,6 +46,10 @@ type fakeCS struct {
|
||||
sub func(rev, app []*types.TipSet)
|
||||
}
|
||||
|
||||
func (fcs *fakeCS) ChainHead(ctx context.Context) (*types.TipSet, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (fcs *fakeCS) ChainGetTipSet(ctx context.Context, key types.TipSetKey) (*types.TipSet, error) {
|
||||
return fcs.tipsets[key], nil
|
||||
}
|
||||
@@ -110,7 +114,11 @@ func (fcs *fakeCS) makeTs(t *testing.T, parents []cid.Cid, h abi.ChainEpoch, msg
|
||||
|
||||
func (fcs *fakeCS) ChainNotify(context.Context) (<-chan []*api.HeadChange, error) {
|
||||
out := make(chan []*api.HeadChange, 1)
|
||||
out <- []*api.HeadChange{{Type: store.HCCurrent, Val: fcs.tsc.best()}}
|
||||
best, err := fcs.tsc.best()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out <- []*api.HeadChange{{Type: store.HCCurrent, Val: best}}
|
||||
|
||||
fcs.sub = func(rev, app []*types.TipSet) {
|
||||
notif := make([]*api.HeadChange, len(rev)+len(app))
|
||||
@@ -174,7 +182,8 @@ func (fcs *fakeCS) advance(rev, app int, msgs map[int]cid.Cid, nulls ...int) { /
|
||||
|
||||
var revs []*types.TipSet
|
||||
for i := 0; i < rev; i++ {
|
||||
ts := fcs.tsc.best()
|
||||
ts, err := fcs.tsc.best()
|
||||
require.NoError(fcs.t, err)
|
||||
|
||||
if _, ok := nullm[int(ts.Height())]; !ok {
|
||||
revs = append(revs, ts)
|
||||
@@ -196,7 +205,9 @@ func (fcs *fakeCS) advance(rev, app int, msgs map[int]cid.Cid, nulls ...int) { /
|
||||
continue
|
||||
}
|
||||
|
||||
ts := fcs.makeTs(fcs.t, fcs.tsc.best().Key().Cids(), fcs.h, mc)
|
||||
best, err := fcs.tsc.best()
|
||||
require.NoError(fcs.t, err)
|
||||
ts := fcs.makeTs(fcs.t, best.Key().Cids(), fcs.h, mc)
|
||||
require.NoError(fcs.t, fcs.tsc.add(ts))
|
||||
|
||||
if hasMsgs {
|
||||
@@ -561,9 +572,9 @@ func TestAtChainedConfidenceNull(t *testing.T) {
|
||||
require.Equal(t, false, reverted)
|
||||
}
|
||||
|
||||
func matchAddrMethod(to address.Address, m abi.MethodNum) func(msg *types.Message) (bool, error) {
|
||||
return func(msg *types.Message) (bool, error) {
|
||||
return to == msg.To && m == msg.Method, nil
|
||||
func matchAddrMethod(to address.Address, m abi.MethodNum) func(msg *types.Message) (matchOnce bool, matched bool, err error) {
|
||||
return func(msg *types.Message) (matchOnce bool, matched bool, err error) {
|
||||
return true, to == msg.To && m == msg.Method, nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package state
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
typegen "github.com/whyrusleeping/cbor-gen"
|
||||
)
|
||||
@@ -39,8 +41,11 @@ func DiffAdtArray(preArr, curArr *adt.Array, out AdtArrayDiff) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := out.Modify(uint64(i), prevVal, curVal); err != nil {
|
||||
return err
|
||||
// no modification
|
||||
if !bytes.Equal(prevVal.Raw, curVal.Raw) {
|
||||
if err := out.Modify(uint64(i), prevVal, curVal); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return curArr.Delete(uint64(i))
|
||||
@@ -90,8 +95,11 @@ func DiffAdtMap(preMap, curMap *adt.Map, out AdtMapDiff) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := out.Modify(key, prevVal, curVal); err != nil {
|
||||
return err
|
||||
// no modification
|
||||
if !bytes.Equal(prevVal.Raw, curVal.Raw) {
|
||||
if err := out.Modify(key, prevVal, curVal); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return curMap.Delete(k)
|
||||
|
||||
@@ -8,14 +8,13 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
ds "github.com/ipfs/go-datastore"
|
||||
ds_sync "github.com/ipfs/go-datastore/sync"
|
||||
bstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
cbornode "github.com/ipfs/go-ipld-cbor"
|
||||
typegen "github.com/whyrusleeping/cbor-gen"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
bstore "github.com/filecoin-project/lotus/lib/blockstore"
|
||||
)
|
||||
|
||||
func TestDiffAdtArray(t *testing.T) {
|
||||
@@ -41,7 +40,7 @@ func TestDiffAdtArray(t *testing.T) {
|
||||
require.NoError(t, arrB.Set(5, runtime.CBORBytes{8})) // add
|
||||
require.NoError(t, arrB.Set(6, runtime.CBORBytes{9})) // add
|
||||
|
||||
changes := new(TestAdtDiff)
|
||||
changes := new(TestDiffArray)
|
||||
|
||||
assert.NoError(t, DiffAdtArray(arrA, arrB, changes))
|
||||
assert.NotNil(t, changes)
|
||||
@@ -72,38 +71,186 @@ func TestDiffAdtArray(t *testing.T) {
|
||||
assert.EqualValues(t, []byte{1}, changes.Removed[1].val)
|
||||
}
|
||||
|
||||
type adtDiffResult struct {
|
||||
key uint64
|
||||
val runtime.CBORBytes
|
||||
func TestDiffAdtMap(t *testing.T) {
|
||||
ctxstoreA := newContextStore()
|
||||
ctxstoreB := newContextStore()
|
||||
|
||||
mapA := adt.MakeEmptyMap(ctxstoreA)
|
||||
mapB := adt.MakeEmptyMap(ctxstoreB)
|
||||
|
||||
require.NoError(t, mapA.Put(adt.UIntKey(0), runtime.CBORBytes([]byte{0}))) // delete
|
||||
|
||||
require.NoError(t, mapA.Put(adt.UIntKey(1), runtime.CBORBytes([]byte{0}))) // modify
|
||||
require.NoError(t, mapB.Put(adt.UIntKey(1), runtime.CBORBytes([]byte{1})))
|
||||
|
||||
require.NoError(t, mapA.Put(adt.UIntKey(2), runtime.CBORBytes([]byte{1}))) // delete
|
||||
|
||||
require.NoError(t, mapA.Put(adt.UIntKey(3), runtime.CBORBytes([]byte{0}))) // noop
|
||||
require.NoError(t, mapB.Put(adt.UIntKey(3), runtime.CBORBytes([]byte{0})))
|
||||
|
||||
require.NoError(t, mapA.Put(adt.UIntKey(4), runtime.CBORBytes([]byte{0}))) // modify
|
||||
require.NoError(t, mapB.Put(adt.UIntKey(4), runtime.CBORBytes([]byte{6})))
|
||||
|
||||
require.NoError(t, mapB.Put(adt.UIntKey(5), runtime.CBORBytes{8})) // add
|
||||
require.NoError(t, mapB.Put(adt.UIntKey(6), runtime.CBORBytes{9})) // add
|
||||
|
||||
changes := new(TestDiffMap)
|
||||
|
||||
assert.NoError(t, DiffAdtMap(mapA, mapB, changes))
|
||||
assert.NotNil(t, changes)
|
||||
|
||||
assert.Equal(t, 2, len(changes.Added))
|
||||
// keys 5 and 6 were added
|
||||
assert.EqualValues(t, uint64(6), changes.Added[0].key)
|
||||
assert.EqualValues(t, []byte{9}, changes.Added[0].val)
|
||||
assert.EqualValues(t, uint64(5), changes.Added[1].key)
|
||||
assert.EqualValues(t, []byte{8}, changes.Added[1].val)
|
||||
|
||||
assert.Equal(t, 2, len(changes.Modified))
|
||||
// keys 1 and 4 were modified
|
||||
assert.EqualValues(t, uint64(1), changes.Modified[0].From.key)
|
||||
assert.EqualValues(t, []byte{0}, changes.Modified[0].From.val)
|
||||
assert.EqualValues(t, uint64(1), changes.Modified[0].To.key)
|
||||
assert.EqualValues(t, []byte{1}, changes.Modified[0].To.val)
|
||||
assert.EqualValues(t, uint64(4), changes.Modified[1].From.key)
|
||||
assert.EqualValues(t, []byte{0}, changes.Modified[1].From.val)
|
||||
assert.EqualValues(t, uint64(4), changes.Modified[1].To.key)
|
||||
assert.EqualValues(t, []byte{6}, changes.Modified[1].To.val)
|
||||
|
||||
assert.Equal(t, 2, len(changes.Removed))
|
||||
// keys 0 and 2 were deleted
|
||||
assert.EqualValues(t, uint64(0), changes.Removed[0].key)
|
||||
assert.EqualValues(t, []byte{0}, changes.Removed[0].val)
|
||||
assert.EqualValues(t, uint64(2), changes.Removed[1].key)
|
||||
assert.EqualValues(t, []byte{1}, changes.Removed[1].val)
|
||||
|
||||
}
|
||||
|
||||
type TestAdtDiff struct {
|
||||
Added []adtDiffResult
|
||||
Modified []TestAdtDiffModified
|
||||
Removed []adtDiffResult
|
||||
type TestDiffMap struct {
|
||||
Added []adtMapDiffResult
|
||||
Modified []TestAdtMapDiffModified
|
||||
Removed []adtMapDiffResult
|
||||
}
|
||||
|
||||
var _ AdtArrayDiff = &TestAdtDiff{}
|
||||
var _ AdtMapDiff = &TestDiffMap{}
|
||||
|
||||
type TestAdtDiffModified struct {
|
||||
From adtDiffResult
|
||||
To adtDiffResult
|
||||
func (t *TestDiffMap) AsKey(key string) (adt.Keyer, error) {
|
||||
k, err := adt.ParseUIntKey(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return adt.UIntKey(k), nil
|
||||
}
|
||||
|
||||
func (t *TestAdtDiff) Add(key uint64, val *typegen.Deferred) error {
|
||||
func (t *TestDiffMap) Add(key string, val *typegen.Deferred) error {
|
||||
v := new(runtime.CBORBytes)
|
||||
err := v.UnmarshalCBOR(bytes.NewReader(val.Raw))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.Added = append(t.Added, adtDiffResult{
|
||||
k, err := adt.ParseUIntKey(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.Added = append(t.Added, adtMapDiffResult{
|
||||
key: k,
|
||||
val: *v,
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *TestDiffMap) Modify(key string, from, to *typegen.Deferred) error {
|
||||
vFrom := new(runtime.CBORBytes)
|
||||
err := vFrom.UnmarshalCBOR(bytes.NewReader(from.Raw))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vTo := new(runtime.CBORBytes)
|
||||
err = vTo.UnmarshalCBOR(bytes.NewReader(to.Raw))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
k, err := adt.ParseUIntKey(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !bytes.Equal(*vFrom, *vTo) {
|
||||
t.Modified = append(t.Modified, TestAdtMapDiffModified{
|
||||
From: adtMapDiffResult{
|
||||
key: k,
|
||||
val: *vFrom,
|
||||
},
|
||||
To: adtMapDiffResult{
|
||||
key: k,
|
||||
val: *vTo,
|
||||
},
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *TestDiffMap) Remove(key string, val *typegen.Deferred) error {
|
||||
v := new(runtime.CBORBytes)
|
||||
err := v.UnmarshalCBOR(bytes.NewReader(val.Raw))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
k, err := adt.ParseUIntKey(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.Removed = append(t.Removed, adtMapDiffResult{
|
||||
key: k,
|
||||
val: *v,
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
type adtMapDiffResult struct {
|
||||
key uint64
|
||||
val runtime.CBORBytes
|
||||
}
|
||||
|
||||
type TestAdtMapDiffModified struct {
|
||||
From adtMapDiffResult
|
||||
To adtMapDiffResult
|
||||
}
|
||||
|
||||
type adtArrayDiffResult struct {
|
||||
key uint64
|
||||
val runtime.CBORBytes
|
||||
}
|
||||
|
||||
type TestDiffArray struct {
|
||||
Added []adtArrayDiffResult
|
||||
Modified []TestAdtArrayDiffModified
|
||||
Removed []adtArrayDiffResult
|
||||
}
|
||||
|
||||
var _ AdtArrayDiff = &TestDiffArray{}
|
||||
|
||||
type TestAdtArrayDiffModified struct {
|
||||
From adtArrayDiffResult
|
||||
To adtArrayDiffResult
|
||||
}
|
||||
|
||||
func (t *TestDiffArray) Add(key uint64, val *typegen.Deferred) error {
|
||||
v := new(runtime.CBORBytes)
|
||||
err := v.UnmarshalCBOR(bytes.NewReader(val.Raw))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.Added = append(t.Added, adtArrayDiffResult{
|
||||
key: key,
|
||||
val: *v,
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *TestAdtDiff) Modify(key uint64, from, to *typegen.Deferred) error {
|
||||
func (t *TestDiffArray) Modify(key uint64, from, to *typegen.Deferred) error {
|
||||
vFrom := new(runtime.CBORBytes)
|
||||
err := vFrom.UnmarshalCBOR(bytes.NewReader(from.Raw))
|
||||
if err != nil {
|
||||
@@ -117,12 +264,12 @@ func (t *TestAdtDiff) Modify(key uint64, from, to *typegen.Deferred) error {
|
||||
}
|
||||
|
||||
if !bytes.Equal(*vFrom, *vTo) {
|
||||
t.Modified = append(t.Modified, TestAdtDiffModified{
|
||||
From: adtDiffResult{
|
||||
t.Modified = append(t.Modified, TestAdtArrayDiffModified{
|
||||
From: adtArrayDiffResult{
|
||||
key: key,
|
||||
val: *vFrom,
|
||||
},
|
||||
To: adtDiffResult{
|
||||
To: adtArrayDiffResult{
|
||||
key: key,
|
||||
val: *vTo,
|
||||
},
|
||||
@@ -131,13 +278,13 @@ func (t *TestAdtDiff) Modify(key uint64, from, to *typegen.Deferred) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *TestAdtDiff) Remove(key uint64, val *typegen.Deferred) error {
|
||||
func (t *TestDiffArray) Remove(key uint64, val *typegen.Deferred) error {
|
||||
v := new(runtime.CBORBytes)
|
||||
err := v.UnmarshalCBOR(bytes.NewReader(val.Raw))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.Removed = append(t.Removed, adtDiffResult{
|
||||
t.Removed = append(t.Removed, adtArrayDiffResult{
|
||||
key: key,
|
||||
val: *v,
|
||||
})
|
||||
@@ -146,7 +293,7 @@ func (t *TestAdtDiff) Remove(key uint64, val *typegen.Deferred) error {
|
||||
|
||||
func newContextStore() *contextStore {
|
||||
ctx := context.Background()
|
||||
bs := bstore.NewBlockstore(ds_sync.MutexWrap(ds.NewMapDatastore()))
|
||||
bs := bstore.NewTemporarySync()
|
||||
store := cbornode.NewCborStore(bs)
|
||||
return &contextStore{
|
||||
ctx: ctx,
|
||||
|
||||
@@ -3,17 +3,20 @@ package state
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/market"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
"github.com/ipfs/go-cid"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
typegen "github.com/whyrusleeping/cbor-gen"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/market"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
"github.com/filecoin-project/lotus/api/apibstore"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
@@ -84,6 +87,50 @@ func (sp *StatePredicates) OnStorageMarketActorChanged(diffStorageMarketState Di
|
||||
})
|
||||
}
|
||||
|
||||
type BalanceTables struct {
|
||||
EscrowTable *adt.BalanceTable
|
||||
LockedTable *adt.BalanceTable
|
||||
}
|
||||
|
||||
// DiffBalanceTablesFunc compares two balance tables
|
||||
type DiffBalanceTablesFunc func(ctx context.Context, oldBalanceTable, newBalanceTable BalanceTables) (changed bool, user UserData, err error)
|
||||
|
||||
// OnBalanceChanged runs when the escrow table for available balances changes
|
||||
func (sp *StatePredicates) OnBalanceChanged(diffBalances DiffBalanceTablesFunc) DiffStorageMarketStateFunc {
|
||||
return func(ctx context.Context, oldState *market.State, newState *market.State) (changed bool, user UserData, err error) {
|
||||
if oldState.EscrowTable.Equals(newState.EscrowTable) && oldState.LockedTable.Equals(newState.LockedTable) {
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
ctxStore := &contextStore{
|
||||
ctx: ctx,
|
||||
cst: sp.cst,
|
||||
}
|
||||
|
||||
oldEscrowRoot, err := adt.AsBalanceTable(ctxStore, oldState.EscrowTable)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
oldLockedRoot, err := adt.AsBalanceTable(ctxStore, oldState.LockedTable)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
newEscrowRoot, err := adt.AsBalanceTable(ctxStore, newState.EscrowTable)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
newLockedRoot, err := adt.AsBalanceTable(ctxStore, newState.LockedTable)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
return diffBalances(ctx, BalanceTables{oldEscrowRoot, oldLockedRoot}, BalanceTables{newEscrowRoot, newLockedRoot})
|
||||
}
|
||||
}
|
||||
|
||||
type DiffAdtArraysFunc func(ctx context.Context, oldDealStateRoot, newDealStateRoot *adt.Array) (changed bool, user UserData, err error)
|
||||
|
||||
// OnDealStateChanged calls diffDealStates when the market deal state changes
|
||||
@@ -279,17 +326,22 @@ func (sp *StatePredicates) DealStateChangedForIDs(dealIds []abi.DealID) DiffAdtA
|
||||
var oldDealPtr, newDealPtr *market.DealState
|
||||
var oldDeal, newDeal market.DealState
|
||||
|
||||
_, err := oldDealStateArray.Get(uint64(dealID), &oldDeal)
|
||||
// If the deal has been removed, we just set it to nil
|
||||
found, err := oldDealStateArray.Get(uint64(dealID), &oldDeal)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
oldDealPtr = &oldDeal
|
||||
if found {
|
||||
oldDealPtr = &oldDeal
|
||||
}
|
||||
|
||||
_, err = newDealStateArray.Get(uint64(dealID), &newDeal)
|
||||
found, err = newDealStateArray.Get(uint64(dealID), &newDeal)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
newDealPtr = &newDeal
|
||||
if found {
|
||||
newDealPtr = &newDeal
|
||||
}
|
||||
|
||||
if oldDeal != newDeal {
|
||||
changedDeals[dealID] = DealStateChange{dealID, oldDealPtr, newDealPtr}
|
||||
@@ -302,8 +354,74 @@ func (sp *StatePredicates) DealStateChangedForIDs(dealIds []abi.DealID) DiffAdtA
|
||||
}
|
||||
}
|
||||
|
||||
// ChangedBalances is a set of changes to deal state
|
||||
type ChangedBalances map[address.Address]BalanceChange
|
||||
|
||||
// BalanceChange is a change in balance from -> to
|
||||
type BalanceChange struct {
|
||||
From abi.TokenAmount
|
||||
To abi.TokenAmount
|
||||
}
|
||||
|
||||
// AvailableBalanceChangedForAddresses detects changes in the escrow table for the given addresses
|
||||
func (sp *StatePredicates) AvailableBalanceChangedForAddresses(getAddrs func() []address.Address) DiffBalanceTablesFunc {
|
||||
return func(ctx context.Context, oldBalances, newBalances BalanceTables) (changed bool, user UserData, err error) {
|
||||
changedBalances := make(ChangedBalances)
|
||||
addrs := getAddrs()
|
||||
for _, addr := range addrs {
|
||||
// If the deal has been removed, we just set it to nil
|
||||
oldEscrowBalance, err := oldBalances.EscrowTable.Get(addr)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
oldLockedBalance, err := oldBalances.LockedTable.Get(addr)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
oldBalance := big.Sub(oldEscrowBalance, oldLockedBalance)
|
||||
|
||||
newEscrowBalance, err := newBalances.EscrowTable.Get(addr)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
newLockedBalance, err := newBalances.LockedTable.Get(addr)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
newBalance := big.Sub(newEscrowBalance, newLockedBalance)
|
||||
|
||||
if !oldBalance.Equals(newBalance) {
|
||||
changedBalances[addr] = BalanceChange{oldBalance, newBalance}
|
||||
}
|
||||
}
|
||||
if len(changedBalances) > 0 {
|
||||
return true, changedBalances, nil
|
||||
}
|
||||
return false, nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
type DiffMinerActorStateFunc func(ctx context.Context, oldState *miner.State, newState *miner.State) (changed bool, user UserData, err error)
|
||||
|
||||
func (sp *StatePredicates) OnInitActorChange(diffInitActorState DiffInitActorStateFunc) DiffTipSetKeyFunc {
|
||||
return sp.OnActorStateChanged(builtin.InitActorAddr, func(ctx context.Context, oldActorStateHead, newActorStateHead cid.Cid) (changed bool, user UserData, err error) {
|
||||
var oldState init_.State
|
||||
if err := sp.cst.Get(ctx, oldActorStateHead, &oldState); err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
var newState init_.State
|
||||
if err := sp.cst.Get(ctx, newActorStateHead, &newState); err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
return diffInitActorState(ctx, &oldState, &newState)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func (sp *StatePredicates) OnMinerActorChange(minerAddr address.Address, diffMinerActorState DiffMinerActorStateFunc) DiffTipSetKeyFunc {
|
||||
return sp.OnActorStateChanged(minerAddr, func(ctx context.Context, oldActorStateHead, newActorStateHead cid.Cid) (changed bool, user UserData, err error) {
|
||||
var oldState miner.State
|
||||
@@ -354,7 +472,7 @@ func (m *MinerSectorChanges) Modify(key uint64, from, to *typegen.Deferred) erro
|
||||
return err
|
||||
}
|
||||
|
||||
if siFrom.Info.Expiration != siTo.Info.Expiration {
|
||||
if siFrom.Expiration != siTo.Expiration {
|
||||
m.Extended = append(m.Extended, SectorExtensions{
|
||||
From: *siFrom,
|
||||
To: *siTo,
|
||||
@@ -488,3 +606,182 @@ func (sp *StatePredicates) OnMinerPreCommitChange() DiffMinerActorStateFunc {
|
||||
return true, precommitChanges, nil
|
||||
}
|
||||
}
|
||||
|
||||
// DiffPaymentChannelStateFunc is function that compares two states for the payment channel
|
||||
type DiffPaymentChannelStateFunc func(ctx context.Context, oldState *paych.State, newState *paych.State) (changed bool, user UserData, err error)
|
||||
|
||||
// OnPaymentChannelActorChanged calls diffPaymentChannelState when the state changes for the the payment channel actor
|
||||
func (sp *StatePredicates) OnPaymentChannelActorChanged(paychAddr address.Address, diffPaymentChannelState DiffPaymentChannelStateFunc) DiffTipSetKeyFunc {
|
||||
return sp.OnActorStateChanged(paychAddr, func(ctx context.Context, oldActorStateHead, newActorStateHead cid.Cid) (changed bool, user UserData, err error) {
|
||||
var oldState paych.State
|
||||
if err := sp.cst.Get(ctx, oldActorStateHead, &oldState); err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
var newState paych.State
|
||||
if err := sp.cst.Get(ctx, newActorStateHead, &newState); err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
return diffPaymentChannelState(ctx, &oldState, &newState)
|
||||
})
|
||||
}
|
||||
|
||||
// PayChToSendChange is a difference in the amount to send on a payment channel when the money is collected
|
||||
type PayChToSendChange struct {
|
||||
OldToSend abi.TokenAmount
|
||||
NewToSend abi.TokenAmount
|
||||
}
|
||||
|
||||
// OnToSendAmountChanges monitors changes on the total amount to send from one party to the other on a payment channel
|
||||
func (sp *StatePredicates) OnToSendAmountChanges() DiffPaymentChannelStateFunc {
|
||||
return func(ctx context.Context, oldState *paych.State, newState *paych.State) (changed bool, user UserData, err error) {
|
||||
if oldState.ToSend.Equals(newState.ToSend) {
|
||||
return false, nil, nil
|
||||
}
|
||||
return true, &PayChToSendChange{
|
||||
OldToSend: oldState.ToSend,
|
||||
NewToSend: newState.ToSend,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
type AddressPair struct {
|
||||
ID address.Address
|
||||
PK address.Address
|
||||
}
|
||||
|
||||
type InitActorAddressChanges struct {
|
||||
Added []AddressPair
|
||||
Modified []AddressChange
|
||||
Removed []AddressPair
|
||||
}
|
||||
|
||||
type AddressChange struct {
|
||||
From AddressPair
|
||||
To AddressPair
|
||||
}
|
||||
|
||||
type DiffInitActorStateFunc func(ctx context.Context, oldState *init_.State, newState *init_.State) (changed bool, user UserData, err error)
|
||||
|
||||
func (i *InitActorAddressChanges) AsKey(key string) (adt.Keyer, error) {
|
||||
addr, err := address.NewFromBytes([]byte(key))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return adt.AddrKey(addr), nil
|
||||
}
|
||||
|
||||
func (i *InitActorAddressChanges) Add(key string, val *typegen.Deferred) error {
|
||||
pkAddr, err := address.NewFromBytes([]byte(key))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
id := new(typegen.CborInt)
|
||||
if err := id.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil {
|
||||
return err
|
||||
}
|
||||
idAddr, err := address.NewIDAddress(uint64(*id))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i.Added = append(i.Added, AddressPair{
|
||||
ID: idAddr,
|
||||
PK: pkAddr,
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *InitActorAddressChanges) Modify(key string, from, to *typegen.Deferred) error {
|
||||
pkAddr, err := address.NewFromBytes([]byte(key))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fromID := new(typegen.CborInt)
|
||||
if err := fromID.UnmarshalCBOR(bytes.NewReader(from.Raw)); err != nil {
|
||||
return err
|
||||
}
|
||||
fromIDAddr, err := address.NewIDAddress(uint64(*fromID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
toID := new(typegen.CborInt)
|
||||
if err := toID.UnmarshalCBOR(bytes.NewReader(to.Raw)); err != nil {
|
||||
return err
|
||||
}
|
||||
toIDAddr, err := address.NewIDAddress(uint64(*toID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
i.Modified = append(i.Modified, AddressChange{
|
||||
From: AddressPair{
|
||||
ID: fromIDAddr,
|
||||
PK: pkAddr,
|
||||
},
|
||||
To: AddressPair{
|
||||
ID: toIDAddr,
|
||||
PK: pkAddr,
|
||||
},
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *InitActorAddressChanges) Remove(key string, val *typegen.Deferred) error {
|
||||
pkAddr, err := address.NewFromBytes([]byte(key))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
id := new(typegen.CborInt)
|
||||
if err := id.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil {
|
||||
return err
|
||||
}
|
||||
idAddr, err := address.NewIDAddress(uint64(*id))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i.Removed = append(i.Removed, AddressPair{
|
||||
ID: idAddr,
|
||||
PK: pkAddr,
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sp *StatePredicates) OnAddressMapChange() DiffInitActorStateFunc {
|
||||
return func(ctx context.Context, oldState, newState *init_.State) (changed bool, user UserData, err error) {
|
||||
ctxStore := &contextStore{
|
||||
ctx: ctx,
|
||||
cst: sp.cst,
|
||||
}
|
||||
|
||||
addressChanges := &InitActorAddressChanges{
|
||||
Added: []AddressPair{},
|
||||
Modified: []AddressChange{},
|
||||
Removed: []AddressPair{},
|
||||
}
|
||||
|
||||
if oldState.AddressMap.Equals(newState.AddressMap) {
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
oldAddrs, err := adt.AsMap(ctxStore, oldState.AddressMap)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
newAddrs, err := adt.AsMap(ctxStore, newState.AddressMap)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
if err := DiffAdtMap(oldAddrs, newAddrs, addressChanges); err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
if len(addressChanges.Added)+len(addressChanges.Removed)+len(addressChanges.Modified) == 0 {
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
return true, addressChanges, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,27 +4,25 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/filecoin-project/go-bitfield"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
ds "github.com/ipfs/go-datastore"
|
||||
ds_sync "github.com/ipfs/go-datastore/sync"
|
||||
"github.com/ipfs/go-hamt-ipld"
|
||||
bstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
cbornode "github.com/ipfs/go-ipld-cbor"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-amt-ipld/v2"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/market"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
tutils "github.com/filecoin-project/specs-actors/support/testing"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
bstore "github.com/filecoin-project/lotus/lib/blockstore"
|
||||
)
|
||||
|
||||
var dummyCid cid.Cid
|
||||
@@ -68,8 +66,8 @@ func (m mockAPI) setActor(tsk types.TipSetKey, act *types.Actor) {
|
||||
|
||||
func TestMarketPredicates(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
bs := bstore.NewBlockstore(ds_sync.MutexWrap(ds.NewMapDatastore()))
|
||||
store := cbornode.NewCborStore(bs)
|
||||
bs := bstore.NewTemporarySync()
|
||||
store := adt.WrapStore(ctx, cbornode.NewCborStore(bs))
|
||||
|
||||
oldDeal1 := &market.DealState{
|
||||
SectorStartEpoch: 1,
|
||||
@@ -115,18 +113,23 @@ func TestMarketPredicates(t *testing.T) {
|
||||
abi.DealID(2): oldProp2,
|
||||
}
|
||||
|
||||
oldStateC := createMarketState(ctx, t, store, oldDeals, oldProps)
|
||||
oldBalances := map[address.Address]balance{
|
||||
tutils.NewIDAddr(t, 1): {abi.NewTokenAmount(1000), abi.NewTokenAmount(1000)},
|
||||
tutils.NewIDAddr(t, 2): {abi.NewTokenAmount(2000), abi.NewTokenAmount(500)},
|
||||
tutils.NewIDAddr(t, 3): {abi.NewTokenAmount(3000), abi.NewTokenAmount(2000)},
|
||||
tutils.NewIDAddr(t, 5): {abi.NewTokenAmount(3000), abi.NewTokenAmount(1000)},
|
||||
}
|
||||
|
||||
oldStateC := createMarketState(ctx, t, store, oldDeals, oldProps, oldBalances)
|
||||
|
||||
newDeal1 := &market.DealState{
|
||||
SectorStartEpoch: 1,
|
||||
LastUpdatedEpoch: 3,
|
||||
SlashEpoch: 0,
|
||||
}
|
||||
newDeal2 := &market.DealState{
|
||||
SectorStartEpoch: 4,
|
||||
LastUpdatedEpoch: 6,
|
||||
SlashEpoch: 6,
|
||||
}
|
||||
|
||||
// deal 2 removed
|
||||
|
||||
// added
|
||||
newDeal3 := &market.DealState{
|
||||
SectorStartEpoch: 1,
|
||||
@@ -135,7 +138,7 @@ func TestMarketPredicates(t *testing.T) {
|
||||
}
|
||||
newDeals := map[abi.DealID]*market.DealState{
|
||||
abi.DealID(1): newDeal1,
|
||||
abi.DealID(2): newDeal2,
|
||||
// deal 2 was removed
|
||||
abi.DealID(3): newDeal3,
|
||||
}
|
||||
|
||||
@@ -158,7 +161,14 @@ func TestMarketPredicates(t *testing.T) {
|
||||
abi.DealID(3): newProp3, // new
|
||||
// NB: DealProposals cannot be modified, so don't test that case.
|
||||
}
|
||||
newStateC := createMarketState(ctx, t, store, newDeals, newProps)
|
||||
newBalances := map[address.Address]balance{
|
||||
tutils.NewIDAddr(t, 1): {abi.NewTokenAmount(3000), abi.NewTokenAmount(0)},
|
||||
tutils.NewIDAddr(t, 2): {abi.NewTokenAmount(2000), abi.NewTokenAmount(500)},
|
||||
tutils.NewIDAddr(t, 4): {abi.NewTokenAmount(5000), abi.NewTokenAmount(0)},
|
||||
tutils.NewIDAddr(t, 5): {abi.NewTokenAmount(1000), abi.NewTokenAmount(3000)},
|
||||
}
|
||||
|
||||
newStateC := createMarketState(ctx, t, store, newDeals, newProps, newBalances)
|
||||
|
||||
minerAddr, err := address.NewFromString("t00")
|
||||
require.NoError(t, err)
|
||||
@@ -197,10 +207,17 @@ func TestMarketPredicates(t *testing.T) {
|
||||
t.Fatal("Unexpected change to LastUpdatedEpoch")
|
||||
}
|
||||
deal2 := changedDealIDs[abi.DealID(2)]
|
||||
if deal2.From.SlashEpoch != 0 || deal2.To.SlashEpoch != 6 {
|
||||
t.Fatal("Unexpected change to SlashEpoch")
|
||||
if deal2.From.LastUpdatedEpoch != 5 || deal2.To != nil {
|
||||
t.Fatal("Expected To to be nil")
|
||||
}
|
||||
|
||||
// Diff with non-existent deal.
|
||||
noDeal := []abi.DealID{4}
|
||||
diffNoDealFn := preds.OnStorageMarketActorChanged(preds.OnDealStateChanged(preds.DealStateChangedForIDs(noDeal)))
|
||||
changed, _, err = diffNoDealFn(ctx, oldState.Key(), newState.Key())
|
||||
require.NoError(t, err)
|
||||
require.False(t, changed)
|
||||
|
||||
// Test that OnActorStateChanged does not call the callback if the state has not changed
|
||||
mockAddr, err := address.NewFromString("t01")
|
||||
require.NoError(t, err)
|
||||
@@ -241,16 +258,14 @@ func TestMarketPredicates(t *testing.T) {
|
||||
require.Equal(t, abi.DealID(3), changedDeals.Added[0].ID)
|
||||
require.Equal(t, *newDeal3, changedDeals.Added[0].Deal)
|
||||
|
||||
require.Len(t, changedDeals.Removed, 0)
|
||||
require.Len(t, changedDeals.Removed, 1)
|
||||
|
||||
require.Len(t, changedDeals.Modified, 2)
|
||||
require.Len(t, changedDeals.Modified, 1)
|
||||
require.Equal(t, abi.DealID(1), changedDeals.Modified[0].ID)
|
||||
require.Equal(t, newDeal1, changedDeals.Modified[0].To)
|
||||
require.Equal(t, oldDeal1, changedDeals.Modified[0].From)
|
||||
|
||||
require.Equal(t, abi.DealID(2), changedDeals.Modified[1].ID)
|
||||
require.Equal(t, oldDeal2, changedDeals.Modified[1].From)
|
||||
require.Equal(t, newDeal2, changedDeals.Modified[1].To)
|
||||
require.Equal(t, abi.DealID(2), changedDeals.Removed[0].ID)
|
||||
})
|
||||
|
||||
t.Run("deal proposal array predicate", func(t *testing.T) {
|
||||
@@ -276,12 +291,69 @@ func TestMarketPredicates(t *testing.T) {
|
||||
require.Equal(t, abi.DealID(2), changedProps.Removed[0].ID)
|
||||
require.Equal(t, *oldProp2, changedProps.Removed[0].Proposal)
|
||||
})
|
||||
|
||||
t.Run("balances predicate", func(t *testing.T) {
|
||||
preds := NewStatePredicates(api)
|
||||
|
||||
getAddresses := func() []address.Address {
|
||||
return []address.Address{tutils.NewIDAddr(t, 1), tutils.NewIDAddr(t, 2), tutils.NewIDAddr(t, 3), tutils.NewIDAddr(t, 4)}
|
||||
}
|
||||
diffBalancesFn := preds.OnStorageMarketActorChanged(preds.OnBalanceChanged(preds.AvailableBalanceChangedForAddresses(getAddresses)))
|
||||
|
||||
// Diff a state against itself: expect no change
|
||||
changed, _, err := diffBalancesFn(ctx, oldState.Key(), oldState.Key())
|
||||
require.NoError(t, err)
|
||||
require.False(t, changed)
|
||||
|
||||
// Diff old state against new state
|
||||
changed, valIDs, err := diffBalancesFn(ctx, oldState.Key(), newState.Key())
|
||||
require.NoError(t, err)
|
||||
require.True(t, changed)
|
||||
|
||||
changedBalances, ok := valIDs.(ChangedBalances)
|
||||
require.True(t, ok)
|
||||
require.Len(t, changedBalances, 3)
|
||||
require.Contains(t, changedBalances, tutils.NewIDAddr(t, 1))
|
||||
require.Contains(t, changedBalances, tutils.NewIDAddr(t, 3))
|
||||
require.Contains(t, changedBalances, tutils.NewIDAddr(t, 4))
|
||||
|
||||
balance1 := changedBalances[tutils.NewIDAddr(t, 1)]
|
||||
if !balance1.From.Equals(abi.NewTokenAmount(1000)) || !balance1.To.Equals(abi.NewTokenAmount(3000)) {
|
||||
t.Fatal("Unexpected change to balance")
|
||||
}
|
||||
balance3 := changedBalances[tutils.NewIDAddr(t, 3)]
|
||||
if !balance3.From.Equals(abi.NewTokenAmount(3000)) || !balance3.To.Equals(abi.NewTokenAmount(0)) {
|
||||
t.Fatal("Unexpected change to balance")
|
||||
}
|
||||
balance4 := changedBalances[tutils.NewIDAddr(t, 4)]
|
||||
if !balance4.From.Equals(abi.NewTokenAmount(0)) || !balance4.To.Equals(abi.NewTokenAmount(5000)) {
|
||||
t.Fatal("Unexpected change to balance")
|
||||
}
|
||||
|
||||
// Diff with non-existent address.
|
||||
getNoAddress := func() []address.Address { return []address.Address{tutils.NewIDAddr(t, 6)} }
|
||||
diffNoAddressFn := preds.OnStorageMarketActorChanged(preds.OnBalanceChanged(preds.AvailableBalanceChangedForAddresses(getNoAddress)))
|
||||
changed, _, err = diffNoAddressFn(ctx, oldState.Key(), newState.Key())
|
||||
require.NoError(t, err)
|
||||
require.False(t, changed)
|
||||
|
||||
// Test that OnBalanceChanged does not call the callback if the state has not changed
|
||||
diffDealBalancesFn := preds.OnBalanceChanged(func(context.Context, BalanceTables, BalanceTables) (bool, UserData, error) {
|
||||
t.Fatal("No state change so this should not be called")
|
||||
return false, nil, nil
|
||||
})
|
||||
marketState := createEmptyMarketState(t, store)
|
||||
changed, _, err = diffDealBalancesFn(ctx, marketState, marketState)
|
||||
require.NoError(t, err)
|
||||
require.False(t, changed)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestMinerSectorChange(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
bs := bstore.NewBlockstore(ds_sync.MutexWrap(ds.NewMapDatastore()))
|
||||
store := cbornode.NewCborStore(bs)
|
||||
bs := bstore.NewTemporarySync()
|
||||
store := adt.WrapStore(ctx, cbornode.NewCborStore(bs))
|
||||
|
||||
nextID := uint64(0)
|
||||
nextIDAddrF := func() address.Address {
|
||||
@@ -290,18 +362,18 @@ func TestMinerSectorChange(t *testing.T) {
|
||||
}
|
||||
|
||||
owner, worker := nextIDAddrF(), nextIDAddrF()
|
||||
si0 := newSectorOnChainInfo(0, tutils.MakeCID("0"), big.NewInt(0), abi.ChainEpoch(0), abi.ChainEpoch(10))
|
||||
si1 := newSectorOnChainInfo(1, tutils.MakeCID("1"), big.NewInt(1), abi.ChainEpoch(1), abi.ChainEpoch(11))
|
||||
si2 := newSectorOnChainInfo(2, tutils.MakeCID("2"), big.NewInt(2), abi.ChainEpoch(2), abi.ChainEpoch(11))
|
||||
si0 := newSectorOnChainInfo(0, tutils.MakeCID("0", &miner.SealedCIDPrefix), big.NewInt(0), abi.ChainEpoch(0), abi.ChainEpoch(10))
|
||||
si1 := newSectorOnChainInfo(1, tutils.MakeCID("1", &miner.SealedCIDPrefix), big.NewInt(1), abi.ChainEpoch(1), abi.ChainEpoch(11))
|
||||
si2 := newSectorOnChainInfo(2, tutils.MakeCID("2", &miner.SealedCIDPrefix), big.NewInt(2), abi.ChainEpoch(2), abi.ChainEpoch(11))
|
||||
oldMinerC := createMinerState(ctx, t, store, owner, worker, []miner.SectorOnChainInfo{si0, si1, si2})
|
||||
|
||||
si3 := newSectorOnChainInfo(3, tutils.MakeCID("3"), big.NewInt(3), abi.ChainEpoch(3), abi.ChainEpoch(12))
|
||||
si3 := newSectorOnChainInfo(3, tutils.MakeCID("3", &miner.SealedCIDPrefix), big.NewInt(3), abi.ChainEpoch(3), abi.ChainEpoch(12))
|
||||
// 0 delete
|
||||
// 1 extend
|
||||
// 2 same
|
||||
// 3 added
|
||||
si1Ext := si1
|
||||
si1Ext.Info.Expiration++
|
||||
si1Ext.Expiration++
|
||||
newMinerC := createMinerState(ctx, t, store, owner, worker, []miner.SectorOnChainInfo{si1Ext, si2, si3})
|
||||
|
||||
minerAddr := nextIDAddrF()
|
||||
@@ -373,50 +445,83 @@ func mockTipset(minerAddr address.Address, timestamp uint64) (*types.TipSet, err
|
||||
}})
|
||||
}
|
||||
|
||||
func createMarketState(ctx context.Context, t *testing.T, store *cbornode.BasicIpldStore, deals map[abi.DealID]*market.DealState, props map[abi.DealID]*market.DealProposal) cid.Cid {
|
||||
type balance struct {
|
||||
available abi.TokenAmount
|
||||
locked abi.TokenAmount
|
||||
}
|
||||
|
||||
func createMarketState(ctx context.Context, t *testing.T, store adt.Store, deals map[abi.DealID]*market.DealState, props map[abi.DealID]*market.DealProposal, balances map[address.Address]balance) cid.Cid {
|
||||
dealRootCid := createDealAMT(ctx, t, store, deals)
|
||||
propRootCid := createProposalAMT(ctx, t, store, props)
|
||||
|
||||
balancesCids := createBalanceTable(ctx, t, store, balances)
|
||||
state := createEmptyMarketState(t, store)
|
||||
state.States = dealRootCid
|
||||
state.Proposals = propRootCid
|
||||
state.EscrowTable = balancesCids[0]
|
||||
state.LockedTable = balancesCids[1]
|
||||
|
||||
stateC, err := store.Put(ctx, state)
|
||||
require.NoError(t, err)
|
||||
return stateC
|
||||
}
|
||||
|
||||
func createEmptyMarketState(t *testing.T, store *cbornode.BasicIpldStore) *market.State {
|
||||
emptyArrayCid, err := amt.NewAMT(store).Flush(context.TODO())
|
||||
func createEmptyMarketState(t *testing.T, store adt.Store) *market.State {
|
||||
emptyArrayCid, err := adt.MakeEmptyArray(store).Root()
|
||||
require.NoError(t, err)
|
||||
emptyMap, err := store.Put(context.TODO(), hamt.NewNode(store, hamt.UseTreeBitWidth(5)))
|
||||
emptyMap, err := adt.MakeEmptyMap(store).Root()
|
||||
require.NoError(t, err)
|
||||
return market.ConstructState(emptyArrayCid, emptyMap, emptyMap)
|
||||
}
|
||||
|
||||
func createDealAMT(ctx context.Context, t *testing.T, store *cbornode.BasicIpldStore, deals map[abi.DealID]*market.DealState) cid.Cid {
|
||||
root := amt.NewAMT(store)
|
||||
func createDealAMT(ctx context.Context, t *testing.T, store adt.Store, deals map[abi.DealID]*market.DealState) cid.Cid {
|
||||
root := adt.MakeEmptyArray(store)
|
||||
for dealID, dealState := range deals {
|
||||
err := root.Set(ctx, uint64(dealID), dealState)
|
||||
err := root.Set(uint64(dealID), dealState)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
rootCid, err := root.Flush(ctx)
|
||||
rootCid, err := root.Root()
|
||||
require.NoError(t, err)
|
||||
return rootCid
|
||||
}
|
||||
|
||||
func createProposalAMT(ctx context.Context, t *testing.T, store *cbornode.BasicIpldStore, props map[abi.DealID]*market.DealProposal) cid.Cid {
|
||||
root := amt.NewAMT(store)
|
||||
func createProposalAMT(ctx context.Context, t *testing.T, store adt.Store, props map[abi.DealID]*market.DealProposal) cid.Cid {
|
||||
root := adt.MakeEmptyArray(store)
|
||||
for dealID, prop := range props {
|
||||
err := root.Set(ctx, uint64(dealID), prop)
|
||||
err := root.Set(uint64(dealID), prop)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
rootCid, err := root.Flush(ctx)
|
||||
rootCid, err := root.Root()
|
||||
require.NoError(t, err)
|
||||
return rootCid
|
||||
}
|
||||
|
||||
func createMinerState(ctx context.Context, t *testing.T, store *cbornode.BasicIpldStore, owner, worker address.Address, sectors []miner.SectorOnChainInfo) cid.Cid {
|
||||
func createBalanceTable(ctx context.Context, t *testing.T, store adt.Store, balances map[address.Address]balance) [2]cid.Cid {
|
||||
escrowMapRoot := adt.MakeEmptyMap(store)
|
||||
escrowMapRootCid, err := escrowMapRoot.Root()
|
||||
require.NoError(t, err)
|
||||
escrowRoot, err := adt.AsBalanceTable(store, escrowMapRootCid)
|
||||
require.NoError(t, err)
|
||||
lockedMapRoot := adt.MakeEmptyMap(store)
|
||||
lockedMapRootCid, err := lockedMapRoot.Root()
|
||||
require.NoError(t, err)
|
||||
lockedRoot, err := adt.AsBalanceTable(store, lockedMapRootCid)
|
||||
require.NoError(t, err)
|
||||
|
||||
for addr, balance := range balances {
|
||||
err := escrowRoot.Add(addr, big.Add(balance.available, balance.locked))
|
||||
require.NoError(t, err)
|
||||
err = lockedRoot.Add(addr, balance.locked)
|
||||
require.NoError(t, err)
|
||||
|
||||
}
|
||||
escrowRootCid, err := escrowRoot.Root()
|
||||
require.NoError(t, err)
|
||||
lockedRootCid, err := lockedRoot.Root()
|
||||
require.NoError(t, err)
|
||||
return [2]cid.Cid{escrowRootCid, lockedRootCid}
|
||||
}
|
||||
|
||||
func createMinerState(ctx context.Context, t *testing.T, store adt.Store, owner, worker address.Address, sectors []miner.SectorOnChainInfo) cid.Cid {
|
||||
rootCid := createSectorsAMT(ctx, t, store, sectors)
|
||||
|
||||
state := createEmptyMinerState(ctx, t, store, owner, worker)
|
||||
@@ -427,30 +532,43 @@ func createMinerState(ctx context.Context, t *testing.T, store *cbornode.BasicIp
|
||||
return stateC
|
||||
}
|
||||
|
||||
func createEmptyMinerState(ctx context.Context, t *testing.T, store *cbornode.BasicIpldStore, owner, worker address.Address) *miner.State {
|
||||
emptyArrayCid, err := amt.NewAMT(store).Flush(context.TODO())
|
||||
func createEmptyMinerState(ctx context.Context, t *testing.T, store adt.Store, owner, worker address.Address) *miner.State {
|
||||
emptyArrayCid, err := adt.MakeEmptyArray(store).Root()
|
||||
require.NoError(t, err)
|
||||
emptyMap, err := store.Put(context.TODO(), hamt.NewNode(store, hamt.UseTreeBitWidth(5)))
|
||||
emptyMap, err := adt.MakeEmptyMap(store).Root()
|
||||
require.NoError(t, err)
|
||||
|
||||
emptyDeadlines := miner.ConstructDeadlines()
|
||||
emptyDeadlinesCid, err := store.Put(context.Background(), emptyDeadlines)
|
||||
emptyDeadline, err := store.Put(store.Context(), miner.ConstructDeadline(emptyArrayCid))
|
||||
require.NoError(t, err)
|
||||
|
||||
state, err := miner.ConstructState(emptyArrayCid, emptyMap, emptyDeadlinesCid, owner, worker, abi.PeerID{'1'}, nil, abi.RegisteredSealProof_StackedDrg64GiBV1, 0)
|
||||
emptyVestingFunds := miner.ConstructVestingFunds()
|
||||
emptyVestingFundsCid, err := store.Put(store.Context(), emptyVestingFunds)
|
||||
require.NoError(t, err)
|
||||
|
||||
emptyDeadlines := miner.ConstructDeadlines(emptyDeadline)
|
||||
emptyDeadlinesCid, err := store.Put(store.Context(), emptyDeadlines)
|
||||
require.NoError(t, err)
|
||||
|
||||
minerInfo := emptyMap
|
||||
|
||||
emptyBitfield := bitfield.NewFromSet(nil)
|
||||
emptyBitfieldCid, err := store.Put(store.Context(), emptyBitfield)
|
||||
require.NoError(t, err)
|
||||
|
||||
state, err := miner.ConstructState(minerInfo, 123, emptyBitfieldCid, emptyArrayCid, emptyMap, emptyDeadlinesCid, emptyVestingFundsCid)
|
||||
require.NoError(t, err)
|
||||
return state
|
||||
|
||||
}
|
||||
|
||||
func createSectorsAMT(ctx context.Context, t *testing.T, store *cbornode.BasicIpldStore, sectors []miner.SectorOnChainInfo) cid.Cid {
|
||||
root := amt.NewAMT(store)
|
||||
func createSectorsAMT(ctx context.Context, t *testing.T, store adt.Store, sectors []miner.SectorOnChainInfo) cid.Cid {
|
||||
root := adt.MakeEmptyArray(store)
|
||||
for _, sector := range sectors {
|
||||
sector := sector
|
||||
err := root.Set(ctx, uint64(sector.Info.SectorNumber), §or)
|
||||
err := root.Set(uint64(sector.SectorNumber), §or)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
rootCid, err := root.Flush(ctx)
|
||||
rootCid, err := root.Root()
|
||||
require.NoError(t, err)
|
||||
return rootCid
|
||||
}
|
||||
@@ -459,10 +577,18 @@ func createSectorsAMT(ctx context.Context, t *testing.T, store *cbornode.BasicIp
|
||||
func newSectorOnChainInfo(sectorNo abi.SectorNumber, sealed cid.Cid, weight big.Int, activation, expiration abi.ChainEpoch) miner.SectorOnChainInfo {
|
||||
info := newSectorPreCommitInfo(sectorNo, sealed, expiration)
|
||||
return miner.SectorOnChainInfo{
|
||||
Info: *info,
|
||||
ActivationEpoch: activation,
|
||||
DealWeight: weight,
|
||||
VerifiedDealWeight: weight,
|
||||
SectorNumber: info.SectorNumber,
|
||||
SealProof: info.SealProof,
|
||||
SealedCID: info.SealedCID,
|
||||
DealIDs: info.DealIDs,
|
||||
Expiration: info.Expiration,
|
||||
|
||||
Activation: activation,
|
||||
DealWeight: weight,
|
||||
VerifiedDealWeight: weight,
|
||||
InitialPledge: big.Zero(),
|
||||
ExpectedDayReward: big.Zero(),
|
||||
ExpectedStoragePledge: big.Zero(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+15
-8
@@ -3,13 +3,16 @@ package events
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
type tsByHFunc func(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error)
|
||||
type tsCacheAPI interface {
|
||||
ChainGetTipSetByHeight(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error)
|
||||
ChainHead(context.Context) (*types.TipSet, error)
|
||||
}
|
||||
|
||||
// tipSetCache implements a simple ring-buffer cache to keep track of recent
|
||||
// tipsets
|
||||
@@ -18,10 +21,10 @@ type tipSetCache struct {
|
||||
start int
|
||||
len int
|
||||
|
||||
storage tsByHFunc
|
||||
storage tsCacheAPI
|
||||
}
|
||||
|
||||
func newTSCache(cap abi.ChainEpoch, storage tsByHFunc) *tipSetCache {
|
||||
func newTSCache(cap abi.ChainEpoch, storage tsCacheAPI) *tipSetCache {
|
||||
return &tipSetCache{
|
||||
cache: make([]*types.TipSet, cap),
|
||||
start: 0,
|
||||
@@ -94,7 +97,7 @@ func (tsc *tipSetCache) getNonNull(height abi.ChainEpoch) (*types.TipSet, error)
|
||||
func (tsc *tipSetCache) get(height abi.ChainEpoch) (*types.TipSet, error) {
|
||||
if tsc.len == 0 {
|
||||
log.Warnf("tipSetCache.get: cache is empty, requesting from storage (h=%d)", height)
|
||||
return tsc.storage(context.TODO(), height, types.EmptyTSK)
|
||||
return tsc.storage.ChainGetTipSetByHeight(context.TODO(), height, types.EmptyTSK)
|
||||
}
|
||||
|
||||
headH := tsc.cache[tsc.start].Height()
|
||||
@@ -114,14 +117,18 @@ func (tsc *tipSetCache) get(height abi.ChainEpoch) (*types.TipSet, error) {
|
||||
|
||||
if height < tail.Height() {
|
||||
log.Warnf("tipSetCache.get: requested tipset not in cache, requesting from storage (h=%d; tail=%d)", height, tail.Height())
|
||||
return tsc.storage(context.TODO(), height, tail.Key())
|
||||
return tsc.storage.ChainGetTipSetByHeight(context.TODO(), height, tail.Key())
|
||||
}
|
||||
|
||||
return tsc.cache[normalModulo(tsc.start-int(headH-height), clen)], nil
|
||||
}
|
||||
|
||||
func (tsc *tipSetCache) best() *types.TipSet {
|
||||
return tsc.cache[tsc.start]
|
||||
func (tsc *tipSetCache) best() (*types.TipSet, error) {
|
||||
best := tsc.cache[tsc.start]
|
||||
if best == nil {
|
||||
return tsc.storage.ChainHead(context.TODO())
|
||||
}
|
||||
return best, nil
|
||||
}
|
||||
|
||||
func normalModulo(n, m int) int {
|
||||
|
||||
@@ -4,8 +4,8 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
@@ -13,10 +13,7 @@ import (
|
||||
)
|
||||
|
||||
func TestTsCache(t *testing.T) {
|
||||
tsc := newTSCache(50, func(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error) {
|
||||
t.Fatal("storage call")
|
||||
return &types.TipSet{}, nil
|
||||
})
|
||||
tsc := newTSCache(50, &tsCacheAPIFailOnStorageCall{t: t})
|
||||
|
||||
h := abi.ChainEpoch(75)
|
||||
|
||||
@@ -43,7 +40,12 @@ func TestTsCache(t *testing.T) {
|
||||
|
||||
for i := 0; i < 9000; i++ {
|
||||
if i%90 > 60 {
|
||||
if err := tsc.revert(tsc.best()); err != nil {
|
||||
best, err := tsc.best()
|
||||
if err != nil {
|
||||
t.Fatal(err, "; i:", i)
|
||||
return
|
||||
}
|
||||
if err := tsc.revert(best); err != nil {
|
||||
t.Fatal(err, "; i:", i)
|
||||
return
|
||||
}
|
||||
@@ -55,11 +57,21 @@ func TestTsCache(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
type tsCacheAPIFailOnStorageCall struct {
|
||||
t *testing.T
|
||||
}
|
||||
|
||||
func (tc *tsCacheAPIFailOnStorageCall) ChainGetTipSetByHeight(ctx context.Context, epoch abi.ChainEpoch, key types.TipSetKey) (*types.TipSet, error) {
|
||||
tc.t.Fatal("storage call")
|
||||
return &types.TipSet{}, nil
|
||||
}
|
||||
func (tc *tsCacheAPIFailOnStorageCall) ChainHead(ctx context.Context) (*types.TipSet, error) {
|
||||
tc.t.Fatal("storage call")
|
||||
return &types.TipSet{}, nil
|
||||
}
|
||||
|
||||
func TestTsCacheNulls(t *testing.T) {
|
||||
tsc := newTSCache(50, func(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error) {
|
||||
t.Fatal("storage call")
|
||||
return &types.TipSet{}, nil
|
||||
})
|
||||
tsc := newTSCache(50, &tsCacheAPIFailOnStorageCall{t: t})
|
||||
|
||||
h := abi.ChainEpoch(75)
|
||||
|
||||
@@ -91,7 +103,9 @@ func TestTsCacheNulls(t *testing.T) {
|
||||
add()
|
||||
add()
|
||||
|
||||
require.Equal(t, h-1, tsc.best().Height())
|
||||
best, err := tsc.best()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, h-1, best.Height())
|
||||
|
||||
ts, err := tsc.get(h - 1)
|
||||
require.NoError(t, err)
|
||||
@@ -109,9 +123,17 @@ func TestTsCacheNulls(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, h-8, ts.Height())
|
||||
|
||||
require.NoError(t, tsc.revert(tsc.best()))
|
||||
require.NoError(t, tsc.revert(tsc.best()))
|
||||
require.Equal(t, h-8, tsc.best().Height())
|
||||
best, err = tsc.best()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, tsc.revert(best))
|
||||
|
||||
best, err = tsc.best()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, tsc.revert(best))
|
||||
|
||||
best, err = tsc.best()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, h-8, best.Height())
|
||||
|
||||
h += 50
|
||||
add()
|
||||
@@ -120,3 +142,27 @@ func TestTsCacheNulls(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, h-1, ts.Height())
|
||||
}
|
||||
|
||||
type tsCacheAPIStorageCallCounter struct {
|
||||
t *testing.T
|
||||
chainGetTipSetByHeight int
|
||||
chainHead int
|
||||
}
|
||||
|
||||
func (tc *tsCacheAPIStorageCallCounter) ChainGetTipSetByHeight(ctx context.Context, epoch abi.ChainEpoch, key types.TipSetKey) (*types.TipSet, error) {
|
||||
tc.chainGetTipSetByHeight++
|
||||
return &types.TipSet{}, nil
|
||||
}
|
||||
func (tc *tsCacheAPIStorageCallCounter) ChainHead(ctx context.Context) (*types.TipSet, error) {
|
||||
tc.chainHead++
|
||||
return &types.TipSet{}, nil
|
||||
}
|
||||
|
||||
func TestTsCacheEmpty(t *testing.T) {
|
||||
// Calling best on an empty cache should just call out to the chain API
|
||||
callCounter := &tsCacheAPIStorageCallCounter{t: t}
|
||||
tsc := newTSCache(50, callCounter)
|
||||
_, err := tsc.best()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, callCounter.chainHead)
|
||||
}
|
||||
|
||||
@@ -34,11 +34,11 @@ func (me *messageEvents) CheckMsg(ctx context.Context, smsg types.ChainMsg, hnd
|
||||
}
|
||||
|
||||
func (me *messageEvents) MatchMsg(inmsg *types.Message) MsgMatchFunc {
|
||||
return func(msg *types.Message) (bool, error) {
|
||||
return func(msg *types.Message) (matchOnce bool, matched bool, err error) {
|
||||
if msg.From == inmsg.From && msg.Nonce == inmsg.Nonce && !inmsg.Equals(msg) {
|
||||
return false, xerrors.Errorf("matching msg %s from %s, nonce %d: got duplicate origin/nonce msg %d", inmsg.Cid(), inmsg.From, inmsg.Nonce, msg.Nonce)
|
||||
return true, false, xerrors.Errorf("matching msg %s from %s, nonce %d: got duplicate origin/nonce msg %d", inmsg.Cid(), inmsg.From, inmsg.Nonce, msg.Nonce)
|
||||
}
|
||||
|
||||
return inmsg.Equals(msg), nil
|
||||
return true, inmsg.Equals(msg), nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,49 +1,49 @@
|
||||
// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT.
|
||||
|
||||
package blocksync
|
||||
package exchange
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/ipfs/go-cid"
|
||||
types "github.com/filecoin-project/lotus/chain/types"
|
||||
cid "github.com/ipfs/go-cid"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
xerrors "golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
var _ = xerrors.Errorf
|
||||
|
||||
var lengthBufBlockSyncRequest = []byte{131}
|
||||
var lengthBufRequest = []byte{131}
|
||||
|
||||
func (t *BlockSyncRequest) MarshalCBOR(w io.Writer) error {
|
||||
func (t *Request) MarshalCBOR(w io.Writer) error {
|
||||
if t == nil {
|
||||
_, err := w.Write(cbg.CborNull)
|
||||
return err
|
||||
}
|
||||
if _, err := w.Write(lengthBufBlockSyncRequest); err != nil {
|
||||
if _, err := w.Write(lengthBufRequest); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
scratch := make([]byte, 9)
|
||||
|
||||
// t.Start ([]cid.Cid) (slice)
|
||||
if len(t.Start) > cbg.MaxLength {
|
||||
return xerrors.Errorf("Slice value in field t.Start was too long")
|
||||
// t.Head ([]cid.Cid) (slice)
|
||||
if len(t.Head) > cbg.MaxLength {
|
||||
return xerrors.Errorf("Slice value in field t.Head was too long")
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.Start))); err != nil {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.Head))); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range t.Start {
|
||||
for _, v := range t.Head {
|
||||
if err := cbg.WriteCidBuf(scratch, w, v); err != nil {
|
||||
return xerrors.Errorf("failed writing cid field t.Start: %w", err)
|
||||
return xerrors.Errorf("failed writing cid field t.Head: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// t.RequestLength (uint64) (uint64)
|
||||
// t.Length (uint64) (uint64)
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.RequestLength)); err != nil {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Length)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -56,7 +56,9 @@ func (t *BlockSyncRequest) MarshalCBOR(w io.Writer) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *BlockSyncRequest) UnmarshalCBOR(r io.Reader) error {
|
||||
func (t *Request) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = Request{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
@@ -72,7 +74,7 @@ func (t *BlockSyncRequest) UnmarshalCBOR(r io.Reader) error {
|
||||
return fmt.Errorf("cbor input had wrong number of fields")
|
||||
}
|
||||
|
||||
// t.Start ([]cid.Cid) (slice)
|
||||
// t.Head ([]cid.Cid) (slice)
|
||||
|
||||
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
@@ -80,7 +82,7 @@ func (t *BlockSyncRequest) UnmarshalCBOR(r io.Reader) error {
|
||||
}
|
||||
|
||||
if extra > cbg.MaxLength {
|
||||
return fmt.Errorf("t.Start: array too large (%d)", extra)
|
||||
return fmt.Errorf("t.Head: array too large (%d)", extra)
|
||||
}
|
||||
|
||||
if maj != cbg.MajArray {
|
||||
@@ -88,19 +90,19 @@ func (t *BlockSyncRequest) UnmarshalCBOR(r io.Reader) error {
|
||||
}
|
||||
|
||||
if extra > 0 {
|
||||
t.Start = make([]cid.Cid, extra)
|
||||
t.Head = make([]cid.Cid, extra)
|
||||
}
|
||||
|
||||
for i := 0; i < int(extra); i++ {
|
||||
|
||||
c, err := cbg.ReadCid(br)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("reading cid field t.Start failed: %w", err)
|
||||
return xerrors.Errorf("reading cid field t.Head failed: %w", err)
|
||||
}
|
||||
t.Start[i] = c
|
||||
t.Head[i] = c
|
||||
}
|
||||
|
||||
// t.RequestLength (uint64) (uint64)
|
||||
// t.Length (uint64) (uint64)
|
||||
|
||||
{
|
||||
|
||||
@@ -111,7 +113,7 @@ func (t *BlockSyncRequest) UnmarshalCBOR(r io.Reader) error {
|
||||
if maj != cbg.MajUnsignedInt {
|
||||
return fmt.Errorf("wrong type for uint64 field")
|
||||
}
|
||||
t.RequestLength = uint64(extra)
|
||||
t.Length = uint64(extra)
|
||||
|
||||
}
|
||||
// t.Options (uint64) (uint64)
|
||||
@@ -131,19 +133,37 @@ func (t *BlockSyncRequest) UnmarshalCBOR(r io.Reader) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var lengthBufBlockSyncResponse = []byte{131}
|
||||
var lengthBufResponse = []byte{131}
|
||||
|
||||
func (t *BlockSyncResponse) MarshalCBOR(w io.Writer) error {
|
||||
func (t *Response) MarshalCBOR(w io.Writer) error {
|
||||
if t == nil {
|
||||
_, err := w.Write(cbg.CborNull)
|
||||
return err
|
||||
}
|
||||
if _, err := w.Write(lengthBufBlockSyncResponse); err != nil {
|
||||
if _, err := w.Write(lengthBufResponse); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
scratch := make([]byte, 9)
|
||||
|
||||
// t.Status (blocksync.status) (uint64)
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Status)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.ErrorMessage (string) (string)
|
||||
if len(t.ErrorMessage) > cbg.MaxLength {
|
||||
return xerrors.Errorf("Value in field t.ErrorMessage was too long")
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len(t.ErrorMessage))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.WriteString(w, string(t.ErrorMessage)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.Chain ([]*blocksync.BSTipSet) (slice)
|
||||
if len(t.Chain) > cbg.MaxLength {
|
||||
return xerrors.Errorf("Slice value in field t.Chain was too long")
|
||||
@@ -157,28 +177,12 @@ func (t *BlockSyncResponse) MarshalCBOR(w io.Writer) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// t.Status (uint64) (uint64)
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Status)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.Message (string) (string)
|
||||
if len(t.Message) > cbg.MaxLength {
|
||||
return xerrors.Errorf("Value in field t.Message was too long")
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len(t.Message))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.WriteString(w, t.Message); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *BlockSyncResponse) UnmarshalCBOR(r io.Reader) error {
|
||||
func (t *Response) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = Response{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
@@ -194,6 +198,30 @@ func (t *BlockSyncResponse) UnmarshalCBOR(r io.Reader) error {
|
||||
return fmt.Errorf("cbor input had wrong number of fields")
|
||||
}
|
||||
|
||||
// t.Status (blocksync.status) (uint64)
|
||||
|
||||
{
|
||||
|
||||
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if maj != cbg.MajUnsignedInt {
|
||||
return fmt.Errorf("wrong type for uint64 field")
|
||||
}
|
||||
t.Status = status(extra)
|
||||
|
||||
}
|
||||
// t.ErrorMessage (string) (string)
|
||||
|
||||
{
|
||||
sval, err := cbg.ReadStringBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.ErrorMessage = string(sval)
|
||||
}
|
||||
// t.Chain ([]*blocksync.BSTipSet) (slice)
|
||||
|
||||
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
|
||||
@@ -223,34 +251,296 @@ func (t *BlockSyncResponse) UnmarshalCBOR(r io.Reader) error {
|
||||
t.Chain[i] = &v
|
||||
}
|
||||
|
||||
// t.Status (uint64) (uint64)
|
||||
return nil
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if maj != cbg.MajUnsignedInt {
|
||||
return fmt.Errorf("wrong type for uint64 field")
|
||||
}
|
||||
t.Status = uint64(extra)
|
||||
var lengthBufCompactedMessages = []byte{132}
|
||||
|
||||
func (t *CompactedMessages) MarshalCBOR(w io.Writer) error {
|
||||
if t == nil {
|
||||
_, err := w.Write(cbg.CborNull)
|
||||
return err
|
||||
}
|
||||
if _, err := w.Write(lengthBufCompactedMessages); err != nil {
|
||||
return err
|
||||
}
|
||||
// t.Message (string) (string)
|
||||
|
||||
{
|
||||
sval, err := cbg.ReadStringBuf(br, scratch)
|
||||
if err != nil {
|
||||
scratch := make([]byte, 9)
|
||||
|
||||
// t.Bls ([]*types.Message) (slice)
|
||||
if len(t.Bls) > cbg.MaxLength {
|
||||
return xerrors.Errorf("Slice value in field t.Bls was too long")
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.Bls))); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range t.Bls {
|
||||
if err := v.MarshalCBOR(w); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
t.Message = string(sval)
|
||||
// t.BlsIncludes ([][]uint64) (slice)
|
||||
if len(t.BlsIncludes) > cbg.MaxLength {
|
||||
return xerrors.Errorf("Slice value in field t.BlsIncludes was too long")
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.BlsIncludes))); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range t.BlsIncludes {
|
||||
if len(v) > cbg.MaxLength {
|
||||
return xerrors.Errorf("Slice value in field v was too long")
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(v))); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range v {
|
||||
if err := cbg.CborWriteHeader(w, cbg.MajUnsignedInt, uint64(v)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// t.Secpk ([]*types.SignedMessage) (slice)
|
||||
if len(t.Secpk) > cbg.MaxLength {
|
||||
return xerrors.Errorf("Slice value in field t.Secpk was too long")
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.Secpk))); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range t.Secpk {
|
||||
if err := v.MarshalCBOR(w); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// t.SecpkIncludes ([][]uint64) (slice)
|
||||
if len(t.SecpkIncludes) > cbg.MaxLength {
|
||||
return xerrors.Errorf("Slice value in field t.SecpkIncludes was too long")
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.SecpkIncludes))); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range t.SecpkIncludes {
|
||||
if len(v) > cbg.MaxLength {
|
||||
return xerrors.Errorf("Slice value in field v was too long")
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(v))); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range v {
|
||||
if err := cbg.CborWriteHeader(w, cbg.MajUnsignedInt, uint64(v)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var lengthBufBSTipSet = []byte{133}
|
||||
func (t *CompactedMessages) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = CompactedMessages{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
maj, extra, err := cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if maj != cbg.MajArray {
|
||||
return fmt.Errorf("cbor input should be of type array")
|
||||
}
|
||||
|
||||
if extra != 4 {
|
||||
return fmt.Errorf("cbor input had wrong number of fields")
|
||||
}
|
||||
|
||||
// t.Bls ([]*types.Message) (slice)
|
||||
|
||||
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if extra > cbg.MaxLength {
|
||||
return fmt.Errorf("t.Bls: array too large (%d)", extra)
|
||||
}
|
||||
|
||||
if maj != cbg.MajArray {
|
||||
return fmt.Errorf("expected cbor array")
|
||||
}
|
||||
|
||||
if extra > 0 {
|
||||
t.Bls = make([]*types.Message, extra)
|
||||
}
|
||||
|
||||
for i := 0; i < int(extra); i++ {
|
||||
|
||||
var v types.Message
|
||||
if err := v.UnmarshalCBOR(br); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.Bls[i] = &v
|
||||
}
|
||||
|
||||
// t.BlsIncludes ([][]uint64) (slice)
|
||||
|
||||
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if extra > cbg.MaxLength {
|
||||
return fmt.Errorf("t.BlsIncludes: array too large (%d)", extra)
|
||||
}
|
||||
|
||||
if maj != cbg.MajArray {
|
||||
return fmt.Errorf("expected cbor array")
|
||||
}
|
||||
|
||||
if extra > 0 {
|
||||
t.BlsIncludes = make([][]uint64, extra)
|
||||
}
|
||||
|
||||
for i := 0; i < int(extra); i++ {
|
||||
{
|
||||
var maj byte
|
||||
var extra uint64
|
||||
var err error
|
||||
|
||||
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if extra > cbg.MaxLength {
|
||||
return fmt.Errorf("t.BlsIncludes[i]: array too large (%d)", extra)
|
||||
}
|
||||
|
||||
if maj != cbg.MajArray {
|
||||
return fmt.Errorf("expected cbor array")
|
||||
}
|
||||
|
||||
if extra > 0 {
|
||||
t.BlsIncludes[i] = make([]uint64, extra)
|
||||
}
|
||||
|
||||
for j := 0; j < int(extra); j++ {
|
||||
|
||||
maj, val, err := cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to read uint64 for t.BlsIncludes[i] slice: %w", err)
|
||||
}
|
||||
|
||||
if maj != cbg.MajUnsignedInt {
|
||||
return xerrors.Errorf("value read for array t.BlsIncludes[i] was not a uint, instead got %d", maj)
|
||||
}
|
||||
|
||||
t.BlsIncludes[i][j] = uint64(val)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// t.Secpk ([]*types.SignedMessage) (slice)
|
||||
|
||||
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if extra > cbg.MaxLength {
|
||||
return fmt.Errorf("t.Secpk: array too large (%d)", extra)
|
||||
}
|
||||
|
||||
if maj != cbg.MajArray {
|
||||
return fmt.Errorf("expected cbor array")
|
||||
}
|
||||
|
||||
if extra > 0 {
|
||||
t.Secpk = make([]*types.SignedMessage, extra)
|
||||
}
|
||||
|
||||
for i := 0; i < int(extra); i++ {
|
||||
|
||||
var v types.SignedMessage
|
||||
if err := v.UnmarshalCBOR(br); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.Secpk[i] = &v
|
||||
}
|
||||
|
||||
// t.SecpkIncludes ([][]uint64) (slice)
|
||||
|
||||
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if extra > cbg.MaxLength {
|
||||
return fmt.Errorf("t.SecpkIncludes: array too large (%d)", extra)
|
||||
}
|
||||
|
||||
if maj != cbg.MajArray {
|
||||
return fmt.Errorf("expected cbor array")
|
||||
}
|
||||
|
||||
if extra > 0 {
|
||||
t.SecpkIncludes = make([][]uint64, extra)
|
||||
}
|
||||
|
||||
for i := 0; i < int(extra); i++ {
|
||||
{
|
||||
var maj byte
|
||||
var extra uint64
|
||||
var err error
|
||||
|
||||
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if extra > cbg.MaxLength {
|
||||
return fmt.Errorf("t.SecpkIncludes[i]: array too large (%d)", extra)
|
||||
}
|
||||
|
||||
if maj != cbg.MajArray {
|
||||
return fmt.Errorf("expected cbor array")
|
||||
}
|
||||
|
||||
if extra > 0 {
|
||||
t.SecpkIncludes[i] = make([]uint64, extra)
|
||||
}
|
||||
|
||||
for j := 0; j < int(extra); j++ {
|
||||
|
||||
maj, val, err := cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to read uint64 for t.SecpkIncludes[i] slice: %w", err)
|
||||
}
|
||||
|
||||
if maj != cbg.MajUnsignedInt {
|
||||
return xerrors.Errorf("value read for array t.SecpkIncludes[i] was not a uint, instead got %d", maj)
|
||||
}
|
||||
|
||||
t.SecpkIncludes[i][j] = uint64(val)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var lengthBufBSTipSet = []byte{130}
|
||||
|
||||
func (t *BSTipSet) MarshalCBOR(w io.Writer) error {
|
||||
if t == nil {
|
||||
@@ -277,83 +567,16 @@ func (t *BSTipSet) MarshalCBOR(w io.Writer) error {
|
||||
}
|
||||
}
|
||||
|
||||
// t.BlsMessages ([]*types.Message) (slice)
|
||||
if len(t.BlsMessages) > cbg.MaxLength {
|
||||
return xerrors.Errorf("Slice value in field t.BlsMessages was too long")
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.BlsMessages))); err != nil {
|
||||
// t.Messages (blocksync.CompactedMessages) (struct)
|
||||
if err := t.Messages.MarshalCBOR(w); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range t.BlsMessages {
|
||||
if err := v.MarshalCBOR(w); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// t.BlsMsgIncludes ([][]uint64) (slice)
|
||||
if len(t.BlsMsgIncludes) > cbg.MaxLength {
|
||||
return xerrors.Errorf("Slice value in field t.BlsMsgIncludes was too long")
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.BlsMsgIncludes))); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range t.BlsMsgIncludes {
|
||||
if len(v) > cbg.MaxLength {
|
||||
return xerrors.Errorf("Slice value in field v was too long")
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(v))); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range v {
|
||||
if err := cbg.CborWriteHeader(w, cbg.MajUnsignedInt, uint64(v)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// t.SecpkMessages ([]*types.SignedMessage) (slice)
|
||||
if len(t.SecpkMessages) > cbg.MaxLength {
|
||||
return xerrors.Errorf("Slice value in field t.SecpkMessages was too long")
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.SecpkMessages))); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range t.SecpkMessages {
|
||||
if err := v.MarshalCBOR(w); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// t.SecpkMsgIncludes ([][]uint64) (slice)
|
||||
if len(t.SecpkMsgIncludes) > cbg.MaxLength {
|
||||
return xerrors.Errorf("Slice value in field t.SecpkMsgIncludes was too long")
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.SecpkMsgIncludes))); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range t.SecpkMsgIncludes {
|
||||
if len(v) > cbg.MaxLength {
|
||||
return xerrors.Errorf("Slice value in field v was too long")
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(v))); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range v {
|
||||
if err := cbg.CborWriteHeader(w, cbg.MajUnsignedInt, uint64(v)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *BSTipSet) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = BSTipSet{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
@@ -365,7 +588,7 @@ func (t *BSTipSet) UnmarshalCBOR(r io.Reader) error {
|
||||
return fmt.Errorf("cbor input should be of type array")
|
||||
}
|
||||
|
||||
if extra != 5 {
|
||||
if extra != 2 {
|
||||
return fmt.Errorf("cbor input had wrong number of fields")
|
||||
}
|
||||
|
||||
@@ -398,181 +621,24 @@ func (t *BSTipSet) UnmarshalCBOR(r io.Reader) error {
|
||||
t.Blocks[i] = &v
|
||||
}
|
||||
|
||||
// t.BlsMessages ([]*types.Message) (slice)
|
||||
// t.Messages (blocksync.CompactedMessages) (struct)
|
||||
|
||||
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
{
|
||||
|
||||
if extra > cbg.MaxLength {
|
||||
return fmt.Errorf("t.BlsMessages: array too large (%d)", extra)
|
||||
}
|
||||
|
||||
if maj != cbg.MajArray {
|
||||
return fmt.Errorf("expected cbor array")
|
||||
}
|
||||
|
||||
if extra > 0 {
|
||||
t.BlsMessages = make([]*types.Message, extra)
|
||||
}
|
||||
|
||||
for i := 0; i < int(extra); i++ {
|
||||
|
||||
var v types.Message
|
||||
if err := v.UnmarshalCBOR(br); err != nil {
|
||||
b, err := br.ReadByte()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.BlsMessages[i] = &v
|
||||
}
|
||||
|
||||
// t.BlsMsgIncludes ([][]uint64) (slice)
|
||||
|
||||
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if extra > cbg.MaxLength {
|
||||
return fmt.Errorf("t.BlsMsgIncludes: array too large (%d)", extra)
|
||||
}
|
||||
|
||||
if maj != cbg.MajArray {
|
||||
return fmt.Errorf("expected cbor array")
|
||||
}
|
||||
|
||||
if extra > 0 {
|
||||
t.BlsMsgIncludes = make([][]uint64, extra)
|
||||
}
|
||||
|
||||
for i := 0; i < int(extra); i++ {
|
||||
{
|
||||
var maj byte
|
||||
var extra uint64
|
||||
var err error
|
||||
|
||||
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
if b != cbg.CborNull[0] {
|
||||
if err := br.UnreadByte(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if extra > cbg.MaxLength {
|
||||
return fmt.Errorf("t.BlsMsgIncludes[i]: array too large (%d)", extra)
|
||||
t.Messages = new(CompactedMessages)
|
||||
if err := t.Messages.UnmarshalCBOR(br); err != nil {
|
||||
return xerrors.Errorf("unmarshaling t.Messages pointer: %w", err)
|
||||
}
|
||||
|
||||
if maj != cbg.MajArray {
|
||||
return fmt.Errorf("expected cbor array")
|
||||
}
|
||||
|
||||
if extra > 0 {
|
||||
t.BlsMsgIncludes[i] = make([]uint64, extra)
|
||||
}
|
||||
|
||||
for j := 0; j < int(extra); j++ {
|
||||
|
||||
maj, val, err := cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to read uint64 for t.BlsMsgIncludes[i] slice: %w", err)
|
||||
}
|
||||
|
||||
if maj != cbg.MajUnsignedInt {
|
||||
return xerrors.Errorf("value read for array t.BlsMsgIncludes[i] was not a uint, instead got %d", maj)
|
||||
}
|
||||
|
||||
t.BlsMsgIncludes[i][j] = uint64(val)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// t.SecpkMessages ([]*types.SignedMessage) (slice)
|
||||
|
||||
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if extra > cbg.MaxLength {
|
||||
return fmt.Errorf("t.SecpkMessages: array too large (%d)", extra)
|
||||
}
|
||||
|
||||
if maj != cbg.MajArray {
|
||||
return fmt.Errorf("expected cbor array")
|
||||
}
|
||||
|
||||
if extra > 0 {
|
||||
t.SecpkMessages = make([]*types.SignedMessage, extra)
|
||||
}
|
||||
|
||||
for i := 0; i < int(extra); i++ {
|
||||
|
||||
var v types.SignedMessage
|
||||
if err := v.UnmarshalCBOR(br); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.SecpkMessages[i] = &v
|
||||
}
|
||||
|
||||
// t.SecpkMsgIncludes ([][]uint64) (slice)
|
||||
|
||||
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if extra > cbg.MaxLength {
|
||||
return fmt.Errorf("t.SecpkMsgIncludes: array too large (%d)", extra)
|
||||
}
|
||||
|
||||
if maj != cbg.MajArray {
|
||||
return fmt.Errorf("expected cbor array")
|
||||
}
|
||||
|
||||
if extra > 0 {
|
||||
t.SecpkMsgIncludes = make([][]uint64, extra)
|
||||
}
|
||||
|
||||
for i := 0; i < int(extra); i++ {
|
||||
{
|
||||
var maj byte
|
||||
var extra uint64
|
||||
var err error
|
||||
|
||||
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if extra > cbg.MaxLength {
|
||||
return fmt.Errorf("t.SecpkMsgIncludes[i]: array too large (%d)", extra)
|
||||
}
|
||||
|
||||
if maj != cbg.MajArray {
|
||||
return fmt.Errorf("expected cbor array")
|
||||
}
|
||||
|
||||
if extra > 0 {
|
||||
t.SecpkMsgIncludes[i] = make([]uint64, extra)
|
||||
}
|
||||
|
||||
for j := 0; j < int(extra); j++ {
|
||||
|
||||
maj, val, err := cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to read uint64 for t.SecpkMsgIncludes[i] slice: %w", err)
|
||||
}
|
||||
|
||||
if maj != cbg.MajUnsignedInt {
|
||||
return xerrors.Errorf("value read for array t.SecpkMsgIncludes[i] was not a uint, instead got %d", maj)
|
||||
}
|
||||
|
||||
t.SecpkMsgIncludes[i][j] = uint64(val)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,430 @@
|
||||
package exchange
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/libp2p/go-libp2p-core/host"
|
||||
"github.com/libp2p/go-libp2p-core/network"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
|
||||
"go.opencensus.io/trace"
|
||||
"go.uber.org/fx"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
cborutil "github.com/filecoin-project/go-cbor-util"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
incrt "github.com/filecoin-project/lotus/lib/increadtimeout"
|
||||
"github.com/filecoin-project/lotus/lib/peermgr"
|
||||
)
|
||||
|
||||
// client implements exchange.Client, using the libp2p ChainExchange protocol
|
||||
// as the fetching mechanism.
|
||||
type client struct {
|
||||
// Connection manager used to contact the server.
|
||||
// FIXME: We should have a reduced interface here, initialized
|
||||
// just with our protocol ID, we shouldn't be able to open *any*
|
||||
// connection.
|
||||
host host.Host
|
||||
|
||||
peerTracker *bsPeerTracker
|
||||
}
|
||||
|
||||
var _ Client = (*client)(nil)
|
||||
|
||||
// NewClient creates a new libp2p-based exchange.Client that uses the libp2p
|
||||
// ChainExhange protocol as the fetching mechanism.
|
||||
func NewClient(lc fx.Lifecycle, host host.Host, pmgr peermgr.MaybePeerMgr) Client {
|
||||
return &client{
|
||||
host: host,
|
||||
peerTracker: newPeerTracker(lc, host, pmgr.Mgr),
|
||||
}
|
||||
}
|
||||
|
||||
// Main logic of the client request service. The provided `Request`
|
||||
// is sent to the `singlePeer` if one is indicated or to all available
|
||||
// ones otherwise. The response is processed and validated according
|
||||
// to the `Request` options. Either a `validatedResponse` is returned
|
||||
// (which can be safely accessed), or an `error` that may represent
|
||||
// either a response error status, a failed validation or an internal
|
||||
// error.
|
||||
//
|
||||
// This is the internal single point of entry for all external-facing
|
||||
// APIs, currently we have 3 very heterogeneous services exposed:
|
||||
// * GetBlocks: Headers
|
||||
// * GetFullTipSet: Headers | Messages
|
||||
// * GetChainMessages: Messages
|
||||
// This function handles all the different combinations of the available
|
||||
// request options without disrupting external calls. In the future the
|
||||
// consumers should be forced to use a more standardized service and
|
||||
// adhere to a single API derived from this function.
|
||||
func (c *client) doRequest(ctx context.Context, req *Request, singlePeer *peer.ID) (*validatedResponse, error) {
|
||||
// Validate request.
|
||||
if req.Length == 0 {
|
||||
return nil, xerrors.Errorf("invalid request of length 0")
|
||||
}
|
||||
if req.Length > MaxRequestLength {
|
||||
return nil, xerrors.Errorf("request length (%d) above maximum (%d)",
|
||||
req.Length, MaxRequestLength)
|
||||
}
|
||||
if req.Options == 0 {
|
||||
return nil, xerrors.Errorf("request with no options set")
|
||||
}
|
||||
|
||||
// Generate the list of peers to be queried, either the
|
||||
// `singlePeer` indicated or all peers available (sorted
|
||||
// by an internal peer tracker with some randomness injected).
|
||||
var peers []peer.ID
|
||||
if singlePeer != nil {
|
||||
peers = []peer.ID{*singlePeer}
|
||||
} else {
|
||||
peers = c.getShuffledPeers()
|
||||
if len(peers) == 0 {
|
||||
return nil, xerrors.Errorf("no peers available")
|
||||
}
|
||||
}
|
||||
|
||||
// Try the request for each peer in the list,
|
||||
// return on the first successful response.
|
||||
// FIXME: Doing this serially isn't great, but fetching in parallel
|
||||
// may not be a good idea either. Think about this more.
|
||||
globalTime := build.Clock.Now()
|
||||
// Global time used to track what is the expected time we will need to get
|
||||
// a response if a client fails us.
|
||||
for _, peer := range peers {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, xerrors.Errorf("context cancelled: %w", ctx.Err())
|
||||
default:
|
||||
}
|
||||
|
||||
// Send request, read response.
|
||||
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",
|
||||
peer.String(), err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Process and validate response.
|
||||
validRes, err := c.processResponse(req, res)
|
||||
if err != nil {
|
||||
log.Warnf("processing peer %s response failed: %s",
|
||||
peer.String(), err)
|
||||
continue
|
||||
}
|
||||
|
||||
c.peerTracker.logGlobalSuccess(build.Clock.Since(globalTime))
|
||||
c.host.ConnManager().TagPeer(peer, "bsync", SuccessPeerTagValue)
|
||||
return validRes, nil
|
||||
}
|
||||
|
||||
errString := "doRequest failed for all peers"
|
||||
if singlePeer != nil {
|
||||
errString = fmt.Sprintf("doRequest failed for single peer %s", *singlePeer)
|
||||
}
|
||||
return nil, xerrors.Errorf(errString)
|
||||
}
|
||||
|
||||
// Process and validate response. Check the status, the integrity of the
|
||||
// information returned, and that it matches the request. Extract the information
|
||||
// into a `validatedResponse` for the external-facing APIs to select what they
|
||||
// need.
|
||||
//
|
||||
// We are conflating in the single error returned both status and validation
|
||||
// errors. Peer penalization should happen here then, before returning, so
|
||||
// we can apply the correct penalties depending on the cause of the error.
|
||||
// FIXME: Add the `peer` as argument once we implement penalties.
|
||||
func (c *client) processResponse(req *Request, res *Response) (*validatedResponse, error) {
|
||||
err := res.statusToError()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("status error: %s", err)
|
||||
}
|
||||
|
||||
options := parseOptions(req.Options)
|
||||
if options.noOptionsSet() {
|
||||
// Safety check: this shouldn't have been sent, and even if it did
|
||||
// it should have been caught by the peer in its error status.
|
||||
return nil, xerrors.Errorf("nothing was requested")
|
||||
}
|
||||
|
||||
// Verify that the chain segment returned is in the valid range.
|
||||
// Note that the returned length might be less than requested.
|
||||
resLength := len(res.Chain)
|
||||
if resLength == 0 {
|
||||
return nil, xerrors.Errorf("got no chain in successful response")
|
||||
}
|
||||
if resLength > int(req.Length) {
|
||||
return nil, xerrors.Errorf("got longer response (%d) than requested (%d)",
|
||||
resLength, req.Length)
|
||||
}
|
||||
if resLength < int(req.Length) && res.Status != Partial {
|
||||
return nil, xerrors.Errorf("got less than requested without a proper status: %d", res.Status)
|
||||
}
|
||||
|
||||
validRes := &validatedResponse{}
|
||||
if options.IncludeHeaders {
|
||||
// Check for valid block sets and extract them into `TipSet`s.
|
||||
validRes.tipsets = make([]*types.TipSet, resLength)
|
||||
for i := 0; i < resLength; i++ {
|
||||
validRes.tipsets[i], err = types.NewTipSet(res.Chain[i].Blocks)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("invalid tipset blocks at height (head - %d): %w", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the returned head matches the one requested.
|
||||
if !types.CidArrsEqual(validRes.tipsets[0].Cids(), req.Head) {
|
||||
return nil, xerrors.Errorf("returned chain head does not match request")
|
||||
}
|
||||
|
||||
// Check `TipSet`s are connected (valid chain).
|
||||
for i := 0; i < len(validRes.tipsets)-1; i++ {
|
||||
if validRes.tipsets[i].IsChildOf(validRes.tipsets[i+1]) == false {
|
||||
return nil, fmt.Errorf("tipsets are not connected at height (head - %d)/(head - %d)",
|
||||
i, i+1)
|
||||
// FIXME: Maybe give more information here, like CIDs.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if options.IncludeMessages {
|
||||
validRes.messages = make([]*CompactedMessages, resLength)
|
||||
for i := 0; i < resLength; i++ {
|
||||
if res.Chain[i].Messages == nil {
|
||||
return nil, xerrors.Errorf("no messages included for tipset at height (head - %d)", i)
|
||||
}
|
||||
validRes.messages[i] = res.Chain[i].Messages
|
||||
}
|
||||
|
||||
if options.IncludeHeaders {
|
||||
// If the headers were also returned check that the compression
|
||||
// indexes are valid before `toFullTipSets()` is called by the
|
||||
// consumer.
|
||||
for tipsetIdx := 0; tipsetIdx < resLength; tipsetIdx++ {
|
||||
msgs := res.Chain[tipsetIdx].Messages
|
||||
blocksNum := len(res.Chain[tipsetIdx].Blocks)
|
||||
if len(msgs.BlsIncludes) != blocksNum {
|
||||
return nil, xerrors.Errorf("BlsIncludes (%d) does not match number of blocks (%d)",
|
||||
len(msgs.BlsIncludes), blocksNum)
|
||||
}
|
||||
if len(msgs.SecpkIncludes) != blocksNum {
|
||||
return nil, xerrors.Errorf("SecpkIncludes (%d) does not match number of blocks (%d)",
|
||||
len(msgs.SecpkIncludes), blocksNum)
|
||||
}
|
||||
for blockIdx := 0; blockIdx < blocksNum; blockIdx++ {
|
||||
for _, mi := range msgs.BlsIncludes[blockIdx] {
|
||||
if int(mi) >= len(msgs.Bls) {
|
||||
return nil, xerrors.Errorf("index in BlsIncludes (%d) exceeds number of messages (%d)",
|
||||
mi, len(msgs.Bls))
|
||||
}
|
||||
}
|
||||
for _, mi := range msgs.SecpkIncludes[blockIdx] {
|
||||
if int(mi) >= len(msgs.Secpk) {
|
||||
return nil, xerrors.Errorf("index in SecpkIncludes (%d) exceeds number of messages (%d)",
|
||||
mi, len(msgs.Secpk))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return validRes, nil
|
||||
}
|
||||
|
||||
// GetBlocks implements Client.GetBlocks(). Refer to the godocs there.
|
||||
func (c *client) GetBlocks(ctx context.Context, tsk types.TipSetKey, count int) ([]*types.TipSet, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "bsync.GetBlocks")
|
||||
defer span.End()
|
||||
if span.IsRecordingEvents() {
|
||||
span.AddAttributes(
|
||||
trace.StringAttribute("tipset", fmt.Sprint(tsk.Cids())),
|
||||
trace.Int64Attribute("count", int64(count)),
|
||||
)
|
||||
}
|
||||
|
||||
req := &Request{
|
||||
Head: tsk.Cids(),
|
||||
Length: uint64(count),
|
||||
Options: Headers,
|
||||
}
|
||||
|
||||
validRes, err := c.doRequest(ctx, req, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return validRes.tipsets, nil
|
||||
}
|
||||
|
||||
// GetFullTipSet implements Client.GetFullTipSet(). Refer to the godocs there.
|
||||
func (c *client) GetFullTipSet(ctx context.Context, peer peer.ID, tsk types.TipSetKey) (*store.FullTipSet, error) {
|
||||
// TODO: round robin through these peers on error
|
||||
|
||||
req := &Request{
|
||||
Head: tsk.Cids(),
|
||||
Length: 1,
|
||||
Options: Headers | Messages,
|
||||
}
|
||||
|
||||
validRes, err := c.doRequest(ctx, req, &peer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return validRes.toFullTipSets()[0], nil
|
||||
// If `doRequest` didn't fail we are guaranteed to have at least
|
||||
// *one* tipset here, so it's safe to index directly.
|
||||
}
|
||||
|
||||
// GetChainMessages implements Client.GetChainMessages(). Refer to the godocs there.
|
||||
func (c *client) GetChainMessages(ctx context.Context, head *types.TipSet, length uint64) ([]*CompactedMessages, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "GetChainMessages")
|
||||
if span.IsRecordingEvents() {
|
||||
span.AddAttributes(
|
||||
trace.StringAttribute("tipset", fmt.Sprint(head.Cids())),
|
||||
trace.Int64Attribute("count", int64(length)),
|
||||
)
|
||||
}
|
||||
defer span.End()
|
||||
|
||||
req := &Request{
|
||||
Head: head.Cids(),
|
||||
Length: length,
|
||||
Options: Messages,
|
||||
}
|
||||
|
||||
validRes, err := c.doRequest(ctx, req, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return validRes.messages, nil
|
||||
}
|
||||
|
||||
// Send a request to a peer. Write request in the stream and read the
|
||||
// response back. We do not do any processing of the request/response
|
||||
// here.
|
||||
func (c *client) sendRequestToPeer(ctx context.Context, peer peer.ID, req *Request) (_ *Response, err error) {
|
||||
// Trace code.
|
||||
ctx, span := trace.StartSpan(ctx, "sendRequestToPeer")
|
||||
defer span.End()
|
||||
if span.IsRecordingEvents() {
|
||||
span.AddAttributes(
|
||||
trace.StringAttribute("peer", peer.Pretty()),
|
||||
)
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if span.IsRecordingEvents() {
|
||||
span.SetStatus(trace.Status{
|
||||
Code: 5,
|
||||
Message: err.Error(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}()
|
||||
// -- TRACE --
|
||||
|
||||
supported, err := c.host.Peerstore().SupportsProtocols(peer, BlockSyncProtocolID, ChainExchangeProtocolID)
|
||||
if err != nil {
|
||||
c.RemovePeer(peer)
|
||||
return nil, xerrors.Errorf("failed to get protocols for peer: %w", err)
|
||||
}
|
||||
if len(supported) == 0 || (supported[0] != BlockSyncProtocolID && supported[0] != ChainExchangeProtocolID) {
|
||||
return nil, xerrors.Errorf("peer %s does not support protocols %s",
|
||||
peer, []string{BlockSyncProtocolID, ChainExchangeProtocolID})
|
||||
}
|
||||
|
||||
connectionStart := build.Clock.Now()
|
||||
|
||||
// Open stream to peer.
|
||||
stream, err := c.host.NewStream(
|
||||
network.WithNoDial(ctx, "should already have connection"),
|
||||
peer,
|
||||
ChainExchangeProtocolID, BlockSyncProtocolID)
|
||||
if err != nil {
|
||||
c.RemovePeer(peer)
|
||||
return nil, xerrors.Errorf("failed to open stream to peer: %w", err)
|
||||
}
|
||||
|
||||
// Write request.
|
||||
_ = stream.SetWriteDeadline(time.Now().Add(WriteReqDeadline))
|
||||
if err := cborutil.WriteCborRPC(stream, req); err != nil {
|
||||
_ = stream.SetWriteDeadline(time.Time{})
|
||||
c.peerTracker.logFailure(peer, build.Clock.Since(connectionStart), req.Length)
|
||||
// FIXME: Should we also remove peer here?
|
||||
return nil, err
|
||||
}
|
||||
_ = stream.SetWriteDeadline(time.Time{}) // clear deadline // FIXME: Needs
|
||||
// its own API (https://github.com/libp2p/go-libp2p-core/issues/162).
|
||||
|
||||
// Read response.
|
||||
var res Response
|
||||
err = cborutil.ReadCborRPC(
|
||||
bufio.NewReader(incrt.New(stream, ReadResMinSpeed, ReadResDeadline)),
|
||||
&res)
|
||||
if err != nil {
|
||||
c.peerTracker.logFailure(peer, build.Clock.Since(connectionStart), req.Length)
|
||||
return nil, xerrors.Errorf("failed to read chainxchg response: %w", err)
|
||||
}
|
||||
|
||||
// FIXME: Move all this together at the top using a defer as done elsewhere.
|
||||
// Maybe we need to declare `res` in the signature.
|
||||
if span.IsRecordingEvents() {
|
||||
span.AddAttributes(
|
||||
trace.Int64Attribute("resp_status", int64(res.Status)),
|
||||
trace.StringAttribute("msg", res.ErrorMessage),
|
||||
trace.Int64Attribute("chain_len", int64(len(res.Chain))),
|
||||
)
|
||||
}
|
||||
|
||||
c.peerTracker.logSuccess(peer, build.Clock.Since(connectionStart), uint64(len(res.Chain)))
|
||||
// FIXME: We should really log a success only after we validate the response.
|
||||
// It might be a bit hard to do.
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
// AddPeer implements Client.AddPeer(). Refer to the godocs there.
|
||||
func (c *client) AddPeer(p peer.ID) {
|
||||
c.peerTracker.addPeer(p)
|
||||
}
|
||||
|
||||
// RemovePeer implements Client.RemovePeer(). Refer to the godocs there.
|
||||
func (c *client) RemovePeer(p peer.ID) {
|
||||
c.peerTracker.removePeer(p)
|
||||
}
|
||||
|
||||
// getShuffledPeers returns a preference-sorted set of peers (by latency
|
||||
// and failure counting), shuffling the first few peers so we don't always
|
||||
// pick the same peer.
|
||||
// FIXME: Consider merging with `shufflePrefix()s`.
|
||||
func (c *client) getShuffledPeers() []peer.ID {
|
||||
peers := c.peerTracker.prefSortedPeers()
|
||||
shufflePrefix(peers)
|
||||
return peers
|
||||
}
|
||||
|
||||
func shufflePrefix(peers []peer.ID) {
|
||||
prefix := ShufflePeersPrefix
|
||||
if len(peers) < prefix {
|
||||
prefix = len(peers)
|
||||
}
|
||||
|
||||
buf := make([]peer.ID, prefix)
|
||||
perm := rand.Perm(prefix)
|
||||
for i, v := range perm {
|
||||
buf[i] = peers[v]
|
||||
}
|
||||
|
||||
copy(peers, buf)
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// Package exchange contains the ChainExchange server and client components.
|
||||
//
|
||||
// ChainExchange is the basic chain synchronization protocol of Filecoin.
|
||||
// ChainExchange is an RPC-oriented protocol, with a single operation to
|
||||
// request blocks for now.
|
||||
//
|
||||
// A request contains a start anchor block (referred to with a CID), and a
|
||||
// amount of blocks requested beyond the anchor (including the anchor itself).
|
||||
//
|
||||
// A client can also pass options, encoded as a 64-bit bitfield. Lotus supports
|
||||
// two options at the moment:
|
||||
//
|
||||
// - include block contents
|
||||
// - include block messages
|
||||
//
|
||||
// The response will include a status code, an optional message, and the
|
||||
// response payload in case of success. The payload is a slice of serialized
|
||||
// tipsets.
|
||||
package exchange
|
||||
@@ -0,0 +1,51 @@
|
||||
package exchange
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/libp2p/go-libp2p-core/network"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
// Server is the responder side of the ChainExchange protocol. It accepts
|
||||
// requests from clients and services them by returning the requested
|
||||
// chain data.
|
||||
type Server interface {
|
||||
// HandleStream is the protocol handler to be registered on a libp2p
|
||||
// protocol router.
|
||||
//
|
||||
// In the current version of the protocol, streams are single-use. The
|
||||
// server will read a single Request, and will respond with a single
|
||||
// Response. It will dispose of the stream straight after.
|
||||
HandleStream(stream network.Stream)
|
||||
}
|
||||
|
||||
// Client is the requesting side of the ChainExchange protocol. It acts as
|
||||
// a proxy for other components to request chain data from peers. It is chiefly
|
||||
// used by the Syncer.
|
||||
type Client interface {
|
||||
// GetBlocks fetches block headers from the network, from the provided
|
||||
// tipset *backwards*, returning as many tipsets as the count parameter,
|
||||
// or less.
|
||||
GetBlocks(ctx context.Context, tsk types.TipSetKey, count int) ([]*types.TipSet, error)
|
||||
|
||||
// GetChainMessages fetches messages from the network, from the provided
|
||||
// tipset *backwards*, returning the messages from as many tipsets as the
|
||||
// count parameter, or less.
|
||||
GetChainMessages(ctx context.Context, head *types.TipSet, length uint64) ([]*CompactedMessages, error)
|
||||
|
||||
// GetFullTipSet fetches a full tipset from a given peer. If successful,
|
||||
// the fetched object contains block headers and all messages in full form.
|
||||
GetFullTipSet(ctx context.Context, peer peer.ID, tsk types.TipSetKey) (*store.FullTipSet, error)
|
||||
|
||||
// AddPeer adds a peer to the pool of peers that the Client requests
|
||||
// data from.
|
||||
AddPeer(peer peer.ID)
|
||||
|
||||
// RemovePeer removes a peer from the pool of peers that the Client
|
||||
// requests data from.
|
||||
RemovePeer(peer peer.ID)
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
package exchange
|
||||
|
||||
// FIXME: This needs to be reviewed.
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
host "github.com/libp2p/go-libp2p-core/host"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
"go.uber.org/fx"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/lib/peermgr"
|
||||
)
|
||||
|
||||
type peerStats struct {
|
||||
successes int
|
||||
failures int
|
||||
firstSeen time.Time
|
||||
averageTime time.Duration
|
||||
}
|
||||
|
||||
type bsPeerTracker struct {
|
||||
lk sync.Mutex
|
||||
|
||||
peers map[peer.ID]*peerStats
|
||||
avgGlobalTime time.Duration
|
||||
|
||||
pmgr *peermgr.PeerMgr
|
||||
}
|
||||
|
||||
func newPeerTracker(lc fx.Lifecycle, h host.Host, pmgr *peermgr.PeerMgr) *bsPeerTracker {
|
||||
bsPt := &bsPeerTracker{
|
||||
peers: make(map[peer.ID]*peerStats),
|
||||
pmgr: pmgr,
|
||||
}
|
||||
|
||||
sub, err := h.EventBus().Subscribe(new(peermgr.NewFilPeer))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
for newPeer := range sub.Out() {
|
||||
bsPt.addPeer(newPeer.(peermgr.NewFilPeer).Id)
|
||||
}
|
||||
}()
|
||||
|
||||
lc.Append(fx.Hook{
|
||||
OnStop: func(ctx context.Context) error {
|
||||
return sub.Close()
|
||||
},
|
||||
})
|
||||
|
||||
return bsPt
|
||||
}
|
||||
|
||||
func (bpt *bsPeerTracker) addPeer(p peer.ID) {
|
||||
bpt.lk.Lock()
|
||||
defer bpt.lk.Unlock()
|
||||
if _, ok := bpt.peers[p]; ok {
|
||||
return
|
||||
}
|
||||
bpt.peers[p] = &peerStats{
|
||||
firstSeen: build.Clock.Now(),
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const (
|
||||
// newPeerMul is how much better than average is the new peer assumed to be
|
||||
// less than one to encourouge trying new peers
|
||||
newPeerMul = 0.9
|
||||
)
|
||||
|
||||
func (bpt *bsPeerTracker) prefSortedPeers() []peer.ID {
|
||||
// TODO: this could probably be cached, but as long as its not too many peers, fine for now
|
||||
bpt.lk.Lock()
|
||||
defer bpt.lk.Unlock()
|
||||
out := make([]peer.ID, 0, len(bpt.peers))
|
||||
for p := range bpt.peers {
|
||||
out = append(out, p)
|
||||
}
|
||||
|
||||
// sort by 'expected cost' of requesting data from that peer
|
||||
// additionally handle edge cases where not enough data is available
|
||||
sort.Slice(out, func(i, j int) bool {
|
||||
pi := bpt.peers[out[i]]
|
||||
pj := bpt.peers[out[j]]
|
||||
|
||||
var costI, costJ float64
|
||||
|
||||
getPeerInitLat := func(p peer.ID) float64 {
|
||||
return float64(bpt.avgGlobalTime) * newPeerMul
|
||||
}
|
||||
|
||||
if pi.successes+pi.failures > 0 {
|
||||
failRateI := float64(pi.failures) / float64(pi.failures+pi.successes)
|
||||
costI = float64(pi.averageTime) + failRateI*float64(bpt.avgGlobalTime)
|
||||
} else {
|
||||
costI = getPeerInitLat(out[i])
|
||||
}
|
||||
|
||||
if pj.successes+pj.failures > 0 {
|
||||
failRateJ := float64(pj.failures) / float64(pj.failures+pj.successes)
|
||||
costJ = float64(pj.averageTime) + failRateJ*float64(bpt.avgGlobalTime)
|
||||
} else {
|
||||
costJ = getPeerInitLat(out[j])
|
||||
}
|
||||
|
||||
return costI < costJ
|
||||
})
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
const (
|
||||
// xInvAlpha = (N+1)/2
|
||||
|
||||
localInvAlpha = 10 // 86% of the value is the last 19
|
||||
globalInvAlpha = 25 // 86% of the value is the last 49
|
||||
)
|
||||
|
||||
func (bpt *bsPeerTracker) logGlobalSuccess(dur time.Duration) {
|
||||
bpt.lk.Lock()
|
||||
defer bpt.lk.Unlock()
|
||||
|
||||
if bpt.avgGlobalTime == 0 {
|
||||
bpt.avgGlobalTime = dur
|
||||
return
|
||||
}
|
||||
delta := (dur - bpt.avgGlobalTime) / globalInvAlpha
|
||||
bpt.avgGlobalTime += delta
|
||||
}
|
||||
|
||||
func logTime(pi *peerStats, dur time.Duration) {
|
||||
if pi.averageTime == 0 {
|
||||
pi.averageTime = dur
|
||||
return
|
||||
}
|
||||
delta := (dur - pi.averageTime) / localInvAlpha
|
||||
pi.averageTime += delta
|
||||
|
||||
}
|
||||
|
||||
func (bpt *bsPeerTracker) logSuccess(p peer.ID, dur time.Duration, reqSize uint64) {
|
||||
bpt.lk.Lock()
|
||||
defer bpt.lk.Unlock()
|
||||
|
||||
var pi *peerStats
|
||||
var ok bool
|
||||
if pi, ok = bpt.peers[p]; !ok {
|
||||
log.Warnw("log success called on peer not in tracker", "peerid", p.String())
|
||||
return
|
||||
}
|
||||
|
||||
pi.successes++
|
||||
if reqSize == 0 {
|
||||
reqSize = 1
|
||||
}
|
||||
logTime(pi, dur/time.Duration(reqSize))
|
||||
}
|
||||
|
||||
func (bpt *bsPeerTracker) logFailure(p peer.ID, dur time.Duration, reqSize uint64) {
|
||||
bpt.lk.Lock()
|
||||
defer bpt.lk.Unlock()
|
||||
|
||||
var pi *peerStats
|
||||
var ok bool
|
||||
if pi, ok = bpt.peers[p]; !ok {
|
||||
log.Warn("log failure called on peer not in tracker", "peerid", p.String())
|
||||
return
|
||||
}
|
||||
|
||||
pi.failures++
|
||||
if reqSize == 0 {
|
||||
reqSize = 1
|
||||
}
|
||||
logTime(pi, dur/time.Duration(reqSize))
|
||||
}
|
||||
|
||||
func (bpt *bsPeerTracker) removePeer(p peer.ID) {
|
||||
bpt.lk.Lock()
|
||||
defer bpt.lk.Unlock()
|
||||
delete(bpt.peers, p)
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
package exchange
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
logging "github.com/ipfs/go-log"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
var log = logging.Logger("chainxchg")
|
||||
|
||||
const (
|
||||
// BlockSyncProtocolID is the protocol ID of the former blocksync protocol.
|
||||
// Deprecated.
|
||||
BlockSyncProtocolID = "/fil/sync/blk/0.0.1"
|
||||
|
||||
// ChainExchangeProtocolID is the protocol ID of the chain exchange
|
||||
// protocol.
|
||||
ChainExchangeProtocolID = "/fil/chain/xchg/0.0.1"
|
||||
)
|
||||
|
||||
// FIXME: Bumped from original 800 to this to accommodate `syncFork()`
|
||||
// use of `GetBlocks()`. It seems the expectation of that API is to
|
||||
// fetch any amount of blocks leaving it to the internal logic here
|
||||
// to partition and reassemble the requests if they go above the maximum.
|
||||
// (Also as a consequence of this temporarily removing the `const`
|
||||
// qualifier to avoid "const initializer [...] is not a constant" error.)
|
||||
var MaxRequestLength = uint64(build.ForkLengthThreshold)
|
||||
|
||||
const (
|
||||
// Extracted constants from the code.
|
||||
// FIXME: Should be reviewed and confirmed.
|
||||
SuccessPeerTagValue = 25
|
||||
WriteReqDeadline = 5 * time.Second
|
||||
ReadResDeadline = WriteReqDeadline
|
||||
ReadResMinSpeed = 50 << 10
|
||||
ShufflePeersPrefix = 5
|
||||
WriteResDeadline = 60 * time.Second
|
||||
)
|
||||
|
||||
// FIXME: Rename. Make private.
|
||||
type Request struct {
|
||||
// List of ordered CIDs comprising a `TipSetKey` from where to start
|
||||
// fetching backwards.
|
||||
// FIXME: Consider using `TipSetKey` now (introduced after the creation
|
||||
// of this protocol) instead of converting back and forth.
|
||||
Head []cid.Cid
|
||||
// Number of block sets to fetch from `Head` (inclusive, should always
|
||||
// be in the range `[1, MaxRequestLength]`).
|
||||
Length uint64
|
||||
// Request options, see `Options` type for more details. Compressed
|
||||
// in a single `uint64` to save space.
|
||||
Options uint64
|
||||
}
|
||||
|
||||
// `Request` processed and validated to query the tipsets needed.
|
||||
type validatedRequest struct {
|
||||
head types.TipSetKey
|
||||
length uint64
|
||||
options *parsedOptions
|
||||
}
|
||||
|
||||
// Request options. When fetching the chain segment we can fetch
|
||||
// either block headers, messages, or both.
|
||||
const (
|
||||
Headers = 1 << iota
|
||||
Messages
|
||||
)
|
||||
|
||||
// Decompressed options into separate struct members for easy access
|
||||
// during internal processing..
|
||||
type parsedOptions struct {
|
||||
IncludeHeaders bool
|
||||
IncludeMessages bool
|
||||
}
|
||||
|
||||
func (options *parsedOptions) noOptionsSet() bool {
|
||||
return options.IncludeHeaders == false &&
|
||||
options.IncludeMessages == false
|
||||
}
|
||||
|
||||
func parseOptions(optfield uint64) *parsedOptions {
|
||||
return &parsedOptions{
|
||||
IncludeHeaders: optfield&(uint64(Headers)) != 0,
|
||||
IncludeMessages: optfield&(uint64(Messages)) != 0,
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Rename. Make private.
|
||||
type Response struct {
|
||||
Status status
|
||||
// String that complements the error status when converting to an
|
||||
// internal error (see `statusToError()`).
|
||||
ErrorMessage string
|
||||
|
||||
Chain []*BSTipSet
|
||||
}
|
||||
|
||||
type status uint64
|
||||
|
||||
const (
|
||||
Ok status = 0
|
||||
// We could not fetch all blocks requested (but at least we returned
|
||||
// the `Head` requested). Not considered an error.
|
||||
Partial = 101
|
||||
|
||||
// Errors
|
||||
NotFound = 201
|
||||
GoAway = 202
|
||||
InternalError = 203
|
||||
BadRequest = 204
|
||||
)
|
||||
|
||||
// Convert status to internal error.
|
||||
func (res *Response) statusToError() error {
|
||||
switch res.Status {
|
||||
case Ok, Partial:
|
||||
return nil
|
||||
// FIXME: Consider if we want to not process `Partial` responses
|
||||
// and return an error instead.
|
||||
case NotFound:
|
||||
return xerrors.Errorf("not found")
|
||||
case GoAway:
|
||||
return xerrors.Errorf("not handling 'go away' chainxchg responses yet")
|
||||
case InternalError:
|
||||
return xerrors.Errorf("block sync peer errored: %s", res.ErrorMessage)
|
||||
case BadRequest:
|
||||
return xerrors.Errorf("block sync request invalid: %s", res.ErrorMessage)
|
||||
default:
|
||||
return xerrors.Errorf("unrecognized response code: %d", res.Status)
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Rename.
|
||||
type BSTipSet struct {
|
||||
Blocks []*types.BlockHeader
|
||||
Messages *CompactedMessages
|
||||
}
|
||||
|
||||
// All messages of a single tipset compacted together instead
|
||||
// of grouped by block to save space, since there are normally
|
||||
// many repeated messages per tipset in different blocks.
|
||||
//
|
||||
// `BlsIncludes`/`SecpkIncludes` matches `Bls`/`Secpk` messages
|
||||
// to blocks in the tipsets with the format:
|
||||
// `BlsIncludes[BI][MI]`
|
||||
// * BI: block index in the tipset.
|
||||
// * MI: message index in `Bls` list
|
||||
//
|
||||
// FIXME: The logic to decompress this structure should belong
|
||||
// to itself, not to the consumer.
|
||||
type CompactedMessages struct {
|
||||
Bls []*types.Message
|
||||
BlsIncludes [][]uint64
|
||||
|
||||
Secpk []*types.SignedMessage
|
||||
SecpkIncludes [][]uint64
|
||||
}
|
||||
|
||||
// Response that has been validated according to the protocol
|
||||
// and can be safely accessed.
|
||||
type validatedResponse struct {
|
||||
tipsets []*types.TipSet
|
||||
// List of all messages per tipset (grouped by tipset,
|
||||
// not by block, hence a single index like `tipsets`).
|
||||
messages []*CompactedMessages
|
||||
}
|
||||
|
||||
// Decompress messages and form full tipsets with them. The headers
|
||||
// need to have been requested as well.
|
||||
func (res *validatedResponse) toFullTipSets() []*store.FullTipSet {
|
||||
if len(res.tipsets) == 0 || len(res.tipsets) != len(res.messages) {
|
||||
// This decompression can only be done if both headers and
|
||||
// messages are returned in the response. (The second check
|
||||
// is already implied by the guarantees of `validatedResponse`,
|
||||
// added here just for completeness.)
|
||||
return nil
|
||||
}
|
||||
ftsList := make([]*store.FullTipSet, len(res.tipsets))
|
||||
for tipsetIdx := range res.tipsets {
|
||||
fts := &store.FullTipSet{} // FIXME: We should use the `NewFullTipSet` API.
|
||||
msgs := res.messages[tipsetIdx]
|
||||
for blockIdx, b := range res.tipsets[tipsetIdx].Blocks() {
|
||||
fb := &types.FullBlock{
|
||||
Header: b,
|
||||
}
|
||||
for _, mi := range msgs.BlsIncludes[blockIdx] {
|
||||
fb.BlsMessages = append(fb.BlsMessages, msgs.Bls[mi])
|
||||
}
|
||||
for _, mi := range msgs.SecpkIncludes[blockIdx] {
|
||||
fb.SecpkMessages = append(fb.SecpkMessages, msgs.Secpk[mi])
|
||||
}
|
||||
|
||||
fts.Blocks = append(fts.Blocks, fb)
|
||||
}
|
||||
ftsList[tipsetIdx] = fts
|
||||
}
|
||||
return ftsList
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
package exchange
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"go.opencensus.io/trace"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
cborutil "github.com/filecoin-project/go-cbor-util"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
inet "github.com/libp2p/go-libp2p-core/network"
|
||||
)
|
||||
|
||||
// server implements exchange.Server. It services requests for the
|
||||
// libp2p ChainExchange protocol.
|
||||
type server struct {
|
||||
cs *store.ChainStore
|
||||
}
|
||||
|
||||
var _ Server = (*server)(nil)
|
||||
|
||||
// NewServer creates a new libp2p-based exchange.Server. It services requests
|
||||
// for the libp2p ChainExchange protocol.
|
||||
func NewServer(cs *store.ChainStore) Server {
|
||||
return &server{
|
||||
cs: cs,
|
||||
}
|
||||
}
|
||||
|
||||
// HandleStream implements Server.HandleStream. Refer to the godocs there.
|
||||
func (s *server) HandleStream(stream inet.Stream) {
|
||||
ctx, span := trace.StartSpan(context.Background(), "chainxchg.HandleStream")
|
||||
defer span.End()
|
||||
|
||||
defer stream.Close() //nolint:errcheck
|
||||
|
||||
var req Request
|
||||
if err := cborutil.ReadCborRPC(bufio.NewReader(stream), &req); err != nil {
|
||||
log.Warnf("failed to read block sync request: %s", err)
|
||||
return
|
||||
}
|
||||
log.Infow("block sync request",
|
||||
"start", req.Head, "len", req.Length)
|
||||
|
||||
resp, err := s.processRequest(ctx, &req)
|
||||
if err != nil {
|
||||
log.Warn("failed to process request: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
_ = stream.SetDeadline(time.Now().Add(WriteResDeadline))
|
||||
if err := cborutil.WriteCborRPC(stream, resp); err != nil {
|
||||
_ = stream.SetDeadline(time.Time{})
|
||||
log.Warnw("failed to write back response for handle stream",
|
||||
"err", err, "peer", stream.Conn().RemotePeer())
|
||||
return
|
||||
}
|
||||
_ = stream.SetDeadline(time.Time{})
|
||||
}
|
||||
|
||||
// Validate and service the request. We return either a protocol
|
||||
// response or an internal error.
|
||||
func (s *server) processRequest(ctx context.Context, req *Request) (*Response, error) {
|
||||
validReq, errResponse := validateRequest(ctx, req)
|
||||
if errResponse != nil {
|
||||
// The request did not pass validation, return the response
|
||||
// indicating it.
|
||||
return errResponse, nil
|
||||
}
|
||||
|
||||
return s.serviceRequest(ctx, validReq)
|
||||
}
|
||||
|
||||
// Validate request. We either return a `validatedRequest`, or an error
|
||||
// `Response` indicating why we can't process it. We do not return any
|
||||
// internal errors here, we just signal protocol ones.
|
||||
func validateRequest(ctx context.Context, req *Request) (*validatedRequest, *Response) {
|
||||
_, span := trace.StartSpan(ctx, "chainxchg.ValidateRequest")
|
||||
defer span.End()
|
||||
|
||||
validReq := validatedRequest{}
|
||||
|
||||
validReq.options = parseOptions(req.Options)
|
||||
if validReq.options.noOptionsSet() {
|
||||
return nil, &Response{
|
||||
Status: BadRequest,
|
||||
ErrorMessage: "no options set",
|
||||
}
|
||||
}
|
||||
|
||||
validReq.length = req.Length
|
||||
if validReq.length > MaxRequestLength {
|
||||
return nil, &Response{
|
||||
Status: BadRequest,
|
||||
ErrorMessage: fmt.Sprintf("request length over maximum allowed (%d)",
|
||||
MaxRequestLength),
|
||||
}
|
||||
}
|
||||
if validReq.length == 0 {
|
||||
return nil, &Response{
|
||||
Status: BadRequest,
|
||||
ErrorMessage: "invalid request length of zero",
|
||||
}
|
||||
}
|
||||
|
||||
if len(req.Head) == 0 {
|
||||
return nil, &Response{
|
||||
Status: BadRequest,
|
||||
ErrorMessage: "no cids in request",
|
||||
}
|
||||
}
|
||||
validReq.head = types.NewTipSetKey(req.Head...)
|
||||
|
||||
// FIXME: Add as a defer at the start.
|
||||
span.AddAttributes(
|
||||
trace.BoolAttribute("blocks", validReq.options.IncludeHeaders),
|
||||
trace.BoolAttribute("messages", validReq.options.IncludeMessages),
|
||||
trace.Int64Attribute("reqlen", int64(validReq.length)),
|
||||
)
|
||||
|
||||
return &validReq, nil
|
||||
}
|
||||
|
||||
func (s *server) serviceRequest(ctx context.Context, req *validatedRequest) (*Response, error) {
|
||||
_, span := trace.StartSpan(ctx, "chainxchg.ServiceRequest")
|
||||
defer span.End()
|
||||
|
||||
chain, err := collectChainSegment(s.cs, req)
|
||||
if err != nil {
|
||||
log.Warn("block sync request: collectChainSegment failed: ", err)
|
||||
return &Response{
|
||||
Status: InternalError,
|
||||
ErrorMessage: err.Error(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
status := Ok
|
||||
if len(chain) < int(req.length) {
|
||||
status = Partial
|
||||
}
|
||||
|
||||
return &Response{
|
||||
Chain: chain,
|
||||
Status: status,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func collectChainSegment(cs *store.ChainStore, req *validatedRequest) ([]*BSTipSet, error) {
|
||||
var bstips []*BSTipSet
|
||||
|
||||
cur := req.head
|
||||
for {
|
||||
var bst BSTipSet
|
||||
ts, err := cs.LoadTipSet(cur)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed loading tipset %s: %w", cur, err)
|
||||
}
|
||||
|
||||
if req.options.IncludeHeaders {
|
||||
bst.Blocks = ts.Blocks()
|
||||
}
|
||||
|
||||
if req.options.IncludeMessages {
|
||||
bmsgs, bmincl, smsgs, smincl, err := gatherMessages(cs, ts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("gather messages failed: %w", err)
|
||||
}
|
||||
|
||||
// FIXME: Pass the response to `gatherMessages()` and set all this there.
|
||||
bst.Messages = &CompactedMessages{}
|
||||
bst.Messages.Bls = bmsgs
|
||||
bst.Messages.BlsIncludes = bmincl
|
||||
bst.Messages.Secpk = smsgs
|
||||
bst.Messages.SecpkIncludes = smincl
|
||||
}
|
||||
|
||||
bstips = append(bstips, &bst)
|
||||
|
||||
// If we collected the length requested or if we reached the
|
||||
// start (genesis), then stop.
|
||||
if uint64(len(bstips)) >= req.length || ts.Height() == 0 {
|
||||
return bstips, nil
|
||||
}
|
||||
|
||||
cur = ts.Parents()
|
||||
}
|
||||
}
|
||||
|
||||
func gatherMessages(cs *store.ChainStore, ts *types.TipSet) ([]*types.Message, [][]uint64, []*types.SignedMessage, [][]uint64, error) {
|
||||
blsmsgmap := make(map[cid.Cid]uint64)
|
||||
secpkmsgmap := make(map[cid.Cid]uint64)
|
||||
var secpkincl, blsincl [][]uint64
|
||||
|
||||
var blscids, secpkcids []cid.Cid
|
||||
for _, block := range ts.Blocks() {
|
||||
bc, sc, err := cs.ReadMsgMetaCids(block.Messages)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
|
||||
// FIXME: DRY. Use `chain.Message` interface.
|
||||
bmi := make([]uint64, 0, len(bc))
|
||||
for _, m := range bc {
|
||||
i, ok := blsmsgmap[m]
|
||||
if !ok {
|
||||
i = uint64(len(blscids))
|
||||
blscids = append(blscids, m)
|
||||
blsmsgmap[m] = i
|
||||
}
|
||||
|
||||
bmi = append(bmi, i)
|
||||
}
|
||||
blsincl = append(blsincl, bmi)
|
||||
|
||||
smi := make([]uint64, 0, len(sc))
|
||||
for _, m := range sc {
|
||||
i, ok := secpkmsgmap[m]
|
||||
if !ok {
|
||||
i = uint64(len(secpkcids))
|
||||
secpkcids = append(secpkcids, m)
|
||||
secpkmsgmap[m] = i
|
||||
}
|
||||
|
||||
smi = append(smi, i)
|
||||
}
|
||||
secpkincl = append(secpkincl, smi)
|
||||
}
|
||||
|
||||
blsmsgs, err := cs.LoadMessagesFromCids(blscids)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
|
||||
secpkmsgs, err := cs.LoadSignedMessagesFromCids(secpkcids)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
|
||||
return blsmsgs, blsincl, secpkmsgs, secpkincl, nil
|
||||
}
|
||||
+111
-46
@@ -8,15 +8,16 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime/proof"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
commcid "github.com/filecoin-project/go-fil-commcid"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
saminer "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
block "github.com/ipfs/go-block-format"
|
||||
"github.com/ipfs/go-blockservice"
|
||||
"github.com/ipfs/go-cid"
|
||||
blockstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
offline "github.com/ipfs/go-ipfs-exchange-offline"
|
||||
format "github.com/ipfs/go-ipld-format"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
@@ -35,17 +36,19 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
"github.com/filecoin-project/lotus/cmd/lotus-seed/seed"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
|
||||
"github.com/filecoin-project/lotus/genesis"
|
||||
"github.com/filecoin-project/lotus/lib/blockstore"
|
||||
"github.com/filecoin-project/lotus/lib/sigs"
|
||||
"github.com/filecoin-project/lotus/node/repo"
|
||||
"github.com/filecoin-project/sector-storage/ffiwrapper"
|
||||
)
|
||||
|
||||
var log = logging.Logger("gen")
|
||||
|
||||
const msgsPerBlock = 20
|
||||
|
||||
var ValidWpostForTesting = []abi.PoStProof{{
|
||||
//nolint:deadcode,varcheck
|
||||
var log = logging.Logger("gen")
|
||||
|
||||
var ValidWpostForTesting = []proof.PoStProof{{
|
||||
ProofBytes: []byte("valid proof"),
|
||||
}}
|
||||
|
||||
@@ -56,7 +59,7 @@ type ChainGen struct {
|
||||
|
||||
cs *store.ChainStore
|
||||
|
||||
beacon beacon.RandomBeacon
|
||||
beacon beacon.Schedule
|
||||
|
||||
sm *stmgr.StateManager
|
||||
|
||||
@@ -92,6 +95,31 @@ func (m mybs) Get(c cid.Cid) (block.Block, error) {
|
||||
return b, nil
|
||||
}
|
||||
|
||||
var rootkeyMultisig = genesis.MultisigMeta{
|
||||
Signers: []address.Address{remAccTestKey},
|
||||
Threshold: 1,
|
||||
VestingDuration: 0,
|
||||
VestingStart: 0,
|
||||
}
|
||||
|
||||
var DefaultVerifregRootkeyActor = genesis.Actor{
|
||||
Type: genesis.TMultisig,
|
||||
Balance: big.NewInt(0),
|
||||
Meta: rootkeyMultisig.ActorMeta(),
|
||||
}
|
||||
|
||||
var remAccTestKey, _ = address.NewFromString("t1ceb34gnsc6qk5dt6n7xg6ycwzasjhbxm3iylkiy")
|
||||
var remAccMeta = genesis.MultisigMeta{
|
||||
Signers: []address.Address{remAccTestKey},
|
||||
Threshold: 1,
|
||||
}
|
||||
|
||||
var DefaultRemainderAccountActor = genesis.Actor{
|
||||
Type: genesis.TMultisig,
|
||||
Balance: big.NewInt(0),
|
||||
Meta: remAccMeta.ActorMeta(),
|
||||
}
|
||||
|
||||
func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
||||
saminer.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
|
||||
abi.RegisteredSealProof_StackedDrg2KiBV1: {},
|
||||
@@ -113,7 +141,7 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
||||
return nil, xerrors.Errorf("failed to get blocks datastore: %w", err)
|
||||
}
|
||||
|
||||
bs := mybs{blockstore.NewIdStore(blockstore.NewBlockstore(bds))}
|
||||
bs := mybs{blockstore.NewBlockstore(bds)}
|
||||
|
||||
ks, err := lr.KeyStore()
|
||||
if err != nil {
|
||||
@@ -177,12 +205,12 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
||||
Accounts: []genesis.Actor{
|
||||
{
|
||||
Type: genesis.TAccount,
|
||||
Balance: types.FromFil(40000),
|
||||
Balance: types.FromFil(20_000_000),
|
||||
Meta: (&genesis.AccountMeta{Owner: mk1}).ActorMeta(),
|
||||
},
|
||||
{
|
||||
Type: genesis.TAccount,
|
||||
Balance: types.FromFil(40000),
|
||||
Balance: types.FromFil(20_000_000),
|
||||
Meta: (&genesis.AccountMeta{Owner: mk2}).ActorMeta(),
|
||||
},
|
||||
{
|
||||
@@ -195,8 +223,10 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
||||
*genm1,
|
||||
*genm2,
|
||||
},
|
||||
NetworkName: "",
|
||||
Timestamp: uint64(time.Now().Add(-500 * time.Duration(build.BlockDelaySecs) * time.Second).Unix()),
|
||||
VerifregRootKey: DefaultVerifregRootkeyActor,
|
||||
RemainderAccount: DefaultRemainderAccountActor,
|
||||
NetworkName: "",
|
||||
Timestamp: uint64(build.Clock.Now().Add(-500 * time.Duration(build.BlockDelaySecs) * time.Second).Unix()),
|
||||
}
|
||||
|
||||
genb, err := genesis2.MakeGenesisBlock(context.TODO(), bs, sys, tpl)
|
||||
@@ -222,7 +252,7 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
||||
|
||||
miners := []address.Address{maddr1, maddr2}
|
||||
|
||||
beac := beacon.NewMockBeacon(time.Second)
|
||||
beac := beacon.Schedule{{Start: 0, Beacon: beacon.NewMockBeacon(time.Second)}}
|
||||
//beac, err := drand.NewDrandBeacon(tpl.Timestamp, build.BlockDelaySecs)
|
||||
//if err != nil {
|
||||
//return nil, xerrors.Errorf("creating drand beacon: %w", err)
|
||||
@@ -256,6 +286,10 @@ func NewGenerator() (*ChainGen, error) {
|
||||
return NewGeneratorWithSectors(1)
|
||||
}
|
||||
|
||||
func (cg *ChainGen) StateManager() *stmgr.StateManager {
|
||||
return cg.sm
|
||||
}
|
||||
|
||||
func (cg *ChainGen) SetStateManager(sm *stmgr.StateManager) {
|
||||
cg.sm = sm
|
||||
}
|
||||
@@ -284,7 +318,8 @@ func (cg *ChainGen) GenesisCar() ([]byte, error) {
|
||||
|
||||
func CarWalkFunc(nd format.Node) (out []*format.Link, err error) {
|
||||
for _, link := range nd.Links() {
|
||||
if link.Cid.Prefix().MhType == uint64(commcid.FC_SEALED_V1) || link.Cid.Prefix().MhType == uint64(commcid.FC_UNSEALED_V1) {
|
||||
pref := link.Cid.Prefix()
|
||||
if pref.Codec == cid.FilCommitmentSealed || pref.Codec == cid.FilCommitmentUnsealed {
|
||||
continue
|
||||
}
|
||||
out = append(out, link)
|
||||
@@ -303,7 +338,7 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m add
|
||||
|
||||
prev := mbi.PrevBeaconEntry
|
||||
|
||||
entries, err := beacon.BeaconEntriesForBlock(ctx, cg.beacon, round, prev)
|
||||
entries, err := beacon.BeaconEntriesForBlock(ctx, cg.beacon, round, pts.Height(), prev)
|
||||
if err != nil {
|
||||
return nil, nil, nil, xerrors.Errorf("get beacon entries for block: %w", err)
|
||||
}
|
||||
@@ -323,7 +358,7 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m add
|
||||
return nil, nil, nil, xerrors.Errorf("failed to cbor marshal address: %w", err)
|
||||
}
|
||||
|
||||
if len(entries) == 0 {
|
||||
if round > build.UpgradeSmokeHeight {
|
||||
buf.Write(pts.MinTicket().VRFProof)
|
||||
}
|
||||
|
||||
@@ -362,16 +397,37 @@ func (cg *ChainGen) NextTipSet() (*MinedTipSet, error) {
|
||||
return mts, nil
|
||||
}
|
||||
|
||||
func (cg *ChainGen) NextTipSetFromMiners(base *types.TipSet, miners []address.Address) (*MinedTipSet, error) {
|
||||
var blks []*types.FullBlock
|
||||
func (cg *ChainGen) SetWinningPoStProver(m address.Address, wpp WinningPoStProver) {
|
||||
cg.eppProvs[m] = wpp
|
||||
}
|
||||
|
||||
msgs, err := cg.GetMessages(cg)
|
||||
func (cg *ChainGen) NextTipSetFromMiners(base *types.TipSet, miners []address.Address) (*MinedTipSet, error) {
|
||||
ms, err := cg.GetMessages(cg)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("get random messages: %w", err)
|
||||
}
|
||||
|
||||
msgs := make([][]*types.SignedMessage, len(miners))
|
||||
for i := range msgs {
|
||||
msgs[i] = ms
|
||||
}
|
||||
|
||||
fts, err := cg.NextTipSetFromMinersWithMessages(base, miners, msgs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &MinedTipSet{
|
||||
TipSet: fts,
|
||||
Messages: ms,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (cg *ChainGen) NextTipSetFromMinersWithMessages(base *types.TipSet, miners []address.Address, msgs [][]*types.SignedMessage) (*store.FullTipSet, error) {
|
||||
var blks []*types.FullBlock
|
||||
|
||||
for round := base.Height() + 1; len(blks) == 0; round++ {
|
||||
for _, m := range miners {
|
||||
for mi, m := range miners {
|
||||
bvals, et, ticket, err := cg.nextBlockProof(context.TODO(), base, m, round)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("next block proof: %w", err)
|
||||
@@ -384,7 +440,7 @@ func (cg *ChainGen) NextTipSetFromMiners(base *types.TipSet, miners []address.Ad
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fblk, err := cg.makeBlock(base, m, ticket, et, bvals, round, wpost, msgs)
|
||||
fblk, err := cg.makeBlock(base, m, ticket, et, bvals, round, wpost, msgs[mi])
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("making a block for next tipset failed: %w", err)
|
||||
}
|
||||
@@ -398,17 +454,12 @@ func (cg *ChainGen) NextTipSetFromMiners(base *types.TipSet, miners []address.Ad
|
||||
}
|
||||
}
|
||||
|
||||
fts := store.NewFullTipSet(blks)
|
||||
|
||||
return &MinedTipSet{
|
||||
TipSet: fts,
|
||||
Messages: msgs,
|
||||
}, nil
|
||||
return store.NewFullTipSet(blks), nil
|
||||
}
|
||||
|
||||
func (cg *ChainGen) makeBlock(parents *types.TipSet, m address.Address, vrfticket *types.Ticket,
|
||||
eticket *types.ElectionProof, bvals []types.BeaconEntry, height abi.ChainEpoch,
|
||||
wpost []abi.PoStProof, msgs []*types.SignedMessage) (*types.FullBlock, error) {
|
||||
wpost []proof.PoStProof, msgs []*types.SignedMessage) (*types.FullBlock, error) {
|
||||
|
||||
var ts uint64
|
||||
if cg.Timestamper != nil {
|
||||
@@ -438,7 +489,8 @@ func (cg *ChainGen) makeBlock(parents *types.TipSet, m address.Address, vrfticke
|
||||
// ResyncBankerNonce is used for dealing with messages made when
|
||||
// simulating forks
|
||||
func (cg *ChainGen) ResyncBankerNonce(ts *types.TipSet) error {
|
||||
act, err := cg.sm.GetActor(cg.banker, ts)
|
||||
var act types.Actor
|
||||
err := cg.sm.WithParentState(ts, cg.sm.WithActor(cg.banker, stmgr.GetActor(&act)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -468,8 +520,9 @@ func getRandomMessages(cg *ChainGen) ([]*types.SignedMessage, error) {
|
||||
|
||||
Method: 0,
|
||||
|
||||
GasLimit: 10000,
|
||||
GasPrice: types.NewInt(0),
|
||||
GasLimit: 100_000_000,
|
||||
GasFeeCap: types.NewInt(0),
|
||||
GasPremium: types.NewInt(0),
|
||||
}
|
||||
|
||||
sig, err := cg.w.Sign(context.TODO(), cg.banker, msg.Cid().Bytes())
|
||||
@@ -494,7 +547,8 @@ func (cg *ChainGen) YieldRepo() (repo.Repo, error) {
|
||||
}
|
||||
|
||||
type MiningCheckAPI interface {
|
||||
ChainGetRandomness(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error)
|
||||
ChainGetRandomnessFromBeacon(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error)
|
||||
ChainGetRandomnessFromTickets(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error)
|
||||
|
||||
MinerGetBaseInfo(context.Context, address.Address, abi.ChainEpoch, types.TipSetKey) (*api.MiningBaseInfo, error)
|
||||
|
||||
@@ -505,16 +559,25 @@ type mca struct {
|
||||
w *wallet.Wallet
|
||||
sm *stmgr.StateManager
|
||||
pv ffiwrapper.Verifier
|
||||
bcn beacon.RandomBeacon
|
||||
bcn beacon.Schedule
|
||||
}
|
||||
|
||||
func (mca mca) ChainGetRandomness(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error) {
|
||||
func (mca mca) ChainGetRandomnessFromTickets(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error) {
|
||||
pts, err := mca.sm.ChainStore().LoadTipSet(tsk)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("loading tipset key: %w", err)
|
||||
}
|
||||
|
||||
return mca.sm.ChainStore().GetRandomness(ctx, pts.Cids(), personalization, randEpoch, entropy)
|
||||
return mca.sm.ChainStore().GetChainRandomness(ctx, pts.Cids(), personalization, randEpoch, entropy)
|
||||
}
|
||||
|
||||
func (mca mca) ChainGetRandomnessFromBeacon(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error) {
|
||||
pts, err := mca.sm.ChainStore().LoadTipSet(tsk)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("loading tipset key: %w", err)
|
||||
}
|
||||
|
||||
return mca.sm.ChainStore().GetBeaconRandomness(ctx, pts.Cids(), personalization, randEpoch, entropy)
|
||||
}
|
||||
|
||||
func (mca mca) MinerGetBaseInfo(ctx context.Context, maddr address.Address, epoch abi.ChainEpoch, tsk types.TipSetKey) (*api.MiningBaseInfo, error) {
|
||||
@@ -527,7 +590,7 @@ func (mca mca) WalletSign(ctx context.Context, a address.Address, v []byte) (*cr
|
||||
|
||||
type WinningPoStProver interface {
|
||||
GenerateCandidates(context.Context, abi.PoStRandomness, uint64) ([]uint64, error)
|
||||
ComputeProof(context.Context, []abi.SectorInfo, abi.PoStRandomness) ([]abi.PoStProof, error)
|
||||
ComputeProof(context.Context, []proof.SectorInfo, abi.PoStRandomness) ([]proof.PoStProof, error)
|
||||
}
|
||||
|
||||
type wppProvider struct{}
|
||||
@@ -536,7 +599,7 @@ func (wpp *wppProvider) GenerateCandidates(ctx context.Context, _ abi.PoStRandom
|
||||
return []uint64{0}, nil
|
||||
}
|
||||
|
||||
func (wpp *wppProvider) ComputeProof(context.Context, []abi.SectorInfo, abi.PoStRandomness) ([]abi.PoStProof, error) {
|
||||
func (wpp *wppProvider) ComputeProof(context.Context, []proof.SectorInfo, abi.PoStRandomness) ([]proof.PoStProof, error) {
|
||||
return ValidWpostForTesting, nil
|
||||
}
|
||||
|
||||
@@ -545,7 +608,7 @@ func IsRoundWinner(ctx context.Context, ts *types.TipSet, round abi.ChainEpoch,
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
if err := miner.MarshalCBOR(buf); err != nil {
|
||||
return nil, xerrors.Errorf("failed to cbor marshal address: %w")
|
||||
return nil, xerrors.Errorf("failed to cbor marshal address: %w", err)
|
||||
}
|
||||
|
||||
electionRand, err := store.DrawRandomness(brand.Data, crypto.DomainSeparationTag_ElectionProofProduction, round, buf.Bytes())
|
||||
@@ -558,12 +621,14 @@ func IsRoundWinner(ctx context.Context, ts *types.TipSet, round abi.ChainEpoch,
|
||||
return nil, xerrors.Errorf("failed to compute VRF: %w", err)
|
||||
}
|
||||
|
||||
// TODO: wire in real power
|
||||
if !types.IsTicketWinner(vrfout, mbi.MinerPower, mbi.NetworkPower) {
|
||||
ep := &types.ElectionProof{VRFProof: vrfout}
|
||||
j := ep.ComputeWinCount(mbi.MinerPower, mbi.NetworkPower)
|
||||
ep.WinCount = j
|
||||
if j < 1 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &types.ElectionProof{VRFProof: vrfout}, nil
|
||||
return ep, nil
|
||||
}
|
||||
|
||||
type SignFunc func(context.Context, address.Address, []byte) (*crypto.Signature, error)
|
||||
@@ -601,15 +666,15 @@ type genFakeVerifier struct{}
|
||||
|
||||
var _ ffiwrapper.Verifier = (*genFakeVerifier)(nil)
|
||||
|
||||
func (m genFakeVerifier) VerifySeal(svi abi.SealVerifyInfo) (bool, error) {
|
||||
func (m genFakeVerifier) VerifySeal(svi proof.SealVerifyInfo) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (m genFakeVerifier) VerifyWinningPoSt(ctx context.Context, info abi.WinningPoStVerifyInfo) (bool, error) {
|
||||
func (m genFakeVerifier) VerifyWinningPoSt(ctx context.Context, info proof.WinningPoStVerifyInfo) (bool, error) {
|
||||
panic("not supported")
|
||||
}
|
||||
|
||||
func (m genFakeVerifier) VerifyWindowPoSt(ctx context.Context, info abi.WindowPoStVerifyInfo) (bool, error) {
|
||||
func (m genFakeVerifier) VerifyWindowPoSt(ctx context.Context, info proof.WindowPoStVerifyInfo) (bool, error) {
|
||||
panic("not supported")
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ package gen
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
@@ -39,8 +39,8 @@ func testGeneration(t testing.TB, n int, msgs int, sectors int) {
|
||||
}
|
||||
|
||||
func TestChainGeneration(t *testing.T) {
|
||||
testGeneration(t, 10, 20, 1)
|
||||
testGeneration(t, 10, 20, 25)
|
||||
t.Run("10-20-1", func(t *testing.T) { testGeneration(t, 10, 20, 1) })
|
||||
t.Run("10-20-25", func(t *testing.T) { testGeneration(t, 10, 20, 25) })
|
||||
}
|
||||
|
||||
func BenchmarkChainGeneration(b *testing.B) {
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package genesis
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
|
||||
blocks "github.com/ipfs/go-block-format"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/multiformats/go-multihash"
|
||||
)
|
||||
|
||||
const genesisMultihashString = "1220107d821c25dc0735200249df94a8bebc9c8e489744f86a4ca8919e81f19dcd72"
|
||||
const genesisBlockHex = "a5684461746574696d6573323031372d30352d30352030313a32373a3531674e6574776f726b6846696c65636f696e65546f6b656e6846696c65636f696e6c546f6b656e416d6f756e7473a36b546f74616c537570706c796d322c3030302c3030302c303030664d696e6572736d312c3430302c3030302c3030306c50726f746f636f6c4c616273a36b446576656c6f706d656e746b3330302c3030302c3030306b46756e6472616973696e676b3230302c3030302c3030306a466f756e646174696f6e6b3130302c3030302c303030674d657373616765784854686973206973207468652047656e6573697320426c6f636b206f66207468652046696c65636f696e20446563656e7472616c697a65642053746f72616765204e6574776f726b2e"
|
||||
|
||||
var cidBuilder = cid.V1Builder{Codec: cid.DagCBOR, MhType: multihash.SHA2_256}
|
||||
|
||||
func expectedCid() cid.Cid {
|
||||
mh, err := multihash.FromHexString(genesisMultihashString)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return cid.NewCidV1(cidBuilder.Codec, mh)
|
||||
}
|
||||
|
||||
func getGenesisBlock() (blocks.Block, error) {
|
||||
genesisBlockData, err := hex.DecodeString(genesisBlockHex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
genesisCid, err := cidBuilder.Sum(genesisBlockData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
block, err := blocks.NewBlockWithCid(genesisBlockData, genesisCid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return block, nil
|
||||
}
|
||||
+308
-93
@@ -2,28 +2,37 @@ package genesis
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
|
||||
"github.com/filecoin-project/go-amt-ipld/v2"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/account"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-datastore"
|
||||
bstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/account"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
"github.com/filecoin-project/lotus/genesis"
|
||||
bstore "github.com/filecoin-project/lotus/lib/blockstore"
|
||||
"github.com/filecoin-project/lotus/lib/sigs"
|
||||
)
|
||||
|
||||
const AccountStart = 100
|
||||
@@ -59,8 +68,15 @@ The process:
|
||||
- power.CreateMiner, set msg value to PowerBalance
|
||||
- market.AddFunds with correct value
|
||||
- market.PublishDeals for related sectors
|
||||
- Set precommits
|
||||
- Commit presealed sectors
|
||||
- Set network power in the power actor to what we'll have after genesis creation
|
||||
- Recreate reward actor state with the right power
|
||||
- For each precommitted sector
|
||||
- Get deal weight
|
||||
- Calculate QA Power
|
||||
- Remove fake power from the power actor
|
||||
- Calculate pledge
|
||||
- Precommit
|
||||
- Confirm valid
|
||||
|
||||
Data Types:
|
||||
|
||||
@@ -91,184 +107,354 @@ Genesis: {
|
||||
|
||||
*/
|
||||
|
||||
func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template genesis.Template) (*state.StateTree, error) {
|
||||
func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template genesis.Template) (*state.StateTree, map[address.Address]address.Address, error) {
|
||||
// Create empty state tree
|
||||
|
||||
cst := cbor.NewCborStore(bs)
|
||||
_, err := cst.Put(context.TODO(), []struct{}{})
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("putting empty object: %w", err)
|
||||
return nil, nil, xerrors.Errorf("putting empty object: %w", err)
|
||||
}
|
||||
|
||||
state, err := state.NewStateTree(cst)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("making new state tree: %w", err)
|
||||
}
|
||||
|
||||
emptyobject, err := cst.Put(context.TODO(), []struct{}{})
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed putting empty object: %w", err)
|
||||
return nil, nil, xerrors.Errorf("making new state tree: %w", err)
|
||||
}
|
||||
|
||||
// Create system actor
|
||||
|
||||
sysact, err := SetupSystemActor(bs)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("setup init actor: %w", err)
|
||||
return nil, nil, xerrors.Errorf("setup init actor: %w", err)
|
||||
}
|
||||
if err := state.SetActor(builtin.SystemActorAddr, sysact); err != nil {
|
||||
return nil, xerrors.Errorf("set init actor: %w", err)
|
||||
return nil, nil, xerrors.Errorf("set init actor: %w", err)
|
||||
}
|
||||
|
||||
// Create init actor
|
||||
|
||||
initact, err := SetupInitActor(bs, template.NetworkName, template.Accounts)
|
||||
idStart, initact, keyIDs, err := SetupInitActor(bs, template.NetworkName, template.Accounts, template.VerifregRootKey)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("setup init actor: %w", err)
|
||||
return nil, nil, xerrors.Errorf("setup init actor: %w", err)
|
||||
}
|
||||
if err := state.SetActor(builtin.InitActorAddr, initact); err != nil {
|
||||
return nil, xerrors.Errorf("set init actor: %w", err)
|
||||
return nil, nil, xerrors.Errorf("set init actor: %w", err)
|
||||
}
|
||||
|
||||
// Setup reward
|
||||
rewact, err := SetupRewardActor(bs)
|
||||
// RewardActor's state is overrwritten by SetupStorageMiners
|
||||
rewact, err := SetupRewardActor(bs, big.Zero())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("setup init actor: %w", err)
|
||||
return nil, nil, xerrors.Errorf("setup init actor: %w", err)
|
||||
}
|
||||
|
||||
err = state.SetActor(builtin.RewardActorAddr, rewact)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("set network account actor: %w", err)
|
||||
return nil, nil, xerrors.Errorf("set network account actor: %w", err)
|
||||
}
|
||||
|
||||
// Setup cron
|
||||
cronact, err := SetupCronActor(bs)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("setup cron actor: %w", err)
|
||||
return nil, nil, xerrors.Errorf("setup cron actor: %w", err)
|
||||
}
|
||||
if err := state.SetActor(builtin.CronActorAddr, cronact); err != nil {
|
||||
return nil, xerrors.Errorf("set cron actor: %w", err)
|
||||
return nil, nil, xerrors.Errorf("set cron actor: %w", err)
|
||||
}
|
||||
|
||||
// Create empty power actor
|
||||
spact, err := SetupStoragePowerActor(bs)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("setup storage market actor: %w", err)
|
||||
return nil, nil, xerrors.Errorf("setup storage market actor: %w", err)
|
||||
}
|
||||
if err := state.SetActor(builtin.StoragePowerActorAddr, spact); err != nil {
|
||||
return nil, xerrors.Errorf("set storage market actor: %w", err)
|
||||
return nil, nil, xerrors.Errorf("set storage market actor: %w", err)
|
||||
}
|
||||
|
||||
// Create empty market actor
|
||||
marketact, err := SetupStorageMarketActor(bs)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("setup storage market actor: %w", err)
|
||||
return nil, nil, xerrors.Errorf("setup storage market actor: %w", err)
|
||||
}
|
||||
if err := state.SetActor(builtin.StorageMarketActorAddr, marketact); err != nil {
|
||||
return nil, xerrors.Errorf("set market actor: %w", err)
|
||||
return nil, nil, xerrors.Errorf("set market actor: %w", err)
|
||||
}
|
||||
|
||||
// Create verified registry
|
||||
verifact, err := SetupVerifiedRegistryActor(bs)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("setup storage market actor: %w", err)
|
||||
return nil, nil, xerrors.Errorf("setup storage market actor: %w", err)
|
||||
}
|
||||
if err := state.SetActor(builtin.VerifiedRegistryActorAddr, verifact); err != nil {
|
||||
return nil, xerrors.Errorf("set market actor: %w", err)
|
||||
return nil, nil, xerrors.Errorf("set market actor: %w", err)
|
||||
}
|
||||
|
||||
burntRoot, err := cst.Put(ctx, &account.State{
|
||||
Address: builtin.BurntFundsActorAddr,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, xerrors.Errorf("failed to setup burnt funds actor state: %w", err)
|
||||
}
|
||||
|
||||
// Setup burnt-funds
|
||||
err = state.SetActor(builtin.BurntFundsActorAddr, &types.Actor{
|
||||
Code: builtin.AccountActorCodeID,
|
||||
Balance: types.NewInt(0),
|
||||
Head: emptyobject,
|
||||
Head: burntRoot,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("set burnt funds account actor: %w", err)
|
||||
return nil, nil, xerrors.Errorf("set burnt funds account actor: %w", err)
|
||||
}
|
||||
|
||||
// Create accounts
|
||||
for id, info := range template.Accounts {
|
||||
if info.Type != genesis.TAccount {
|
||||
return nil, xerrors.New("unsupported account type") // TODO: msigs
|
||||
for _, info := range template.Accounts {
|
||||
|
||||
switch info.Type {
|
||||
case genesis.TAccount:
|
||||
if err := createAccountActor(ctx, cst, state, info, keyIDs); err != nil {
|
||||
return nil, nil, xerrors.Errorf("failed to create account actor: %w", err)
|
||||
}
|
||||
|
||||
case genesis.TMultisig:
|
||||
|
||||
ida, err := address.NewIDAddress(uint64(idStart))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
idStart++
|
||||
|
||||
if err := createMultisigAccount(ctx, bs, cst, state, ida, info, keyIDs); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
default:
|
||||
return nil, nil, xerrors.New("unsupported account type")
|
||||
}
|
||||
|
||||
ida, err := address.NewIDAddress(uint64(AccountStart + id))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ainfo genesis.AccountMeta
|
||||
if err := json.Unmarshal(info.Meta, &ainfo); err != nil {
|
||||
return nil, xerrors.Errorf("unmarshaling account meta: %w", err)
|
||||
}
|
||||
|
||||
st, err := cst.Put(ctx, &account.State{Address: ainfo.Owner})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = state.SetActor(ida, &types.Actor{
|
||||
Code: builtin.AccountActorCodeID,
|
||||
Balance: info.Balance,
|
||||
Head: st,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("setting account from actmap: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
vregroot, err := address.NewIDAddress(80)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
vrst, err := cst.Put(ctx, &account.State{Address: RootVerifierAddr})
|
||||
if err = createMultisigAccount(ctx, bs, cst, state, vregroot, template.VerifregRootKey, keyIDs); err != nil {
|
||||
return nil, nil, xerrors.Errorf("failed to set up verified registry signer: %w", err)
|
||||
}
|
||||
|
||||
// Setup the first verifier as ID-address 81
|
||||
// TODO: remove this
|
||||
skBytes, err := sigs.Generate(crypto.SigTypeBLS)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, xerrors.Errorf("creating random verifier secret key: %w", err)
|
||||
}
|
||||
|
||||
err = state.SetActor(vregroot, &types.Actor{
|
||||
verifierPk, err := sigs.ToPublic(crypto.SigTypeBLS, skBytes)
|
||||
if err != nil {
|
||||
return nil, nil, xerrors.Errorf("creating random verifier public key: %w", err)
|
||||
}
|
||||
|
||||
verifierAd, err := address.NewBLSAddress(verifierPk)
|
||||
if err != nil {
|
||||
return nil, nil, xerrors.Errorf("creating random verifier address: %w", err)
|
||||
}
|
||||
|
||||
verifierId, err := address.NewIDAddress(81)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
verifierState, err := cst.Put(ctx, &account.State{Address: verifierAd})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
err = state.SetActor(verifierId, &types.Actor{
|
||||
Code: builtin.AccountActorCodeID,
|
||||
Balance: types.NewInt(0),
|
||||
Head: vrst,
|
||||
Head: verifierState,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("setting account from actmap: %w", err)
|
||||
return nil, nil, xerrors.Errorf("setting account from actmap: %w", err)
|
||||
}
|
||||
|
||||
return state, nil
|
||||
totalFilAllocated := big.Zero()
|
||||
|
||||
// flush as ForEach works on the HAMT
|
||||
if _, err := state.Flush(ctx); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
err = state.ForEach(func(addr address.Address, act *types.Actor) error {
|
||||
totalFilAllocated = big.Add(totalFilAllocated, act.Balance)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, xerrors.Errorf("summing account balances in state tree: %w", err)
|
||||
}
|
||||
|
||||
totalFil := big.Mul(big.NewInt(int64(build.FilBase)), big.NewInt(int64(build.FilecoinPrecision)))
|
||||
remainingFil := big.Sub(totalFil, totalFilAllocated)
|
||||
if remainingFil.Sign() < 0 {
|
||||
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 {
|
||||
return nil, nil, xerrors.Errorf("failed to set up remainder account: %w", err)
|
||||
}
|
||||
|
||||
return state, keyIDs, nil
|
||||
}
|
||||
|
||||
func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot cid.Cid, template genesis.Template) (cid.Cid, error) {
|
||||
func createAccountActor(ctx context.Context, cst cbor.IpldStore, state *state.StateTree, info genesis.Actor, keyIDs map[address.Address]address.Address) error {
|
||||
var ainfo genesis.AccountMeta
|
||||
if err := json.Unmarshal(info.Meta, &ainfo); err != nil {
|
||||
return xerrors.Errorf("unmarshaling account meta: %w", err)
|
||||
}
|
||||
st, err := cst.Put(ctx, &account.State{Address: ainfo.Owner})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ida, ok := keyIDs[ainfo.Owner]
|
||||
if !ok {
|
||||
return fmt.Errorf("no registered ID for account actor: %s", ainfo.Owner)
|
||||
}
|
||||
|
||||
err = state.SetActor(ida, &types.Actor{
|
||||
Code: builtin.AccountActorCodeID,
|
||||
Balance: info.Balance,
|
||||
Head: st,
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("setting account from actmap: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func createMultisigAccount(ctx context.Context, bs bstore.Blockstore, cst cbor.IpldStore, state *state.StateTree, ida address.Address, info genesis.Actor, keyIDs map[address.Address]address.Address) error {
|
||||
if info.Type != genesis.TMultisig {
|
||||
return fmt.Errorf("can only call createMultisigAccount with multisig Actor info")
|
||||
}
|
||||
var ainfo genesis.MultisigMeta
|
||||
if err := json.Unmarshal(info.Meta, &ainfo); err != nil {
|
||||
return xerrors.Errorf("unmarshaling account meta: %w", err)
|
||||
}
|
||||
pending, err := adt.MakeEmptyMap(adt.WrapStore(ctx, cst)).Root()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to create empty map: %v", err)
|
||||
}
|
||||
|
||||
var signers []address.Address
|
||||
|
||||
for _, e := range ainfo.Signers {
|
||||
idAddress, ok := keyIDs[e]
|
||||
if !ok {
|
||||
return fmt.Errorf("no registered key ID for signer: %s", e)
|
||||
}
|
||||
|
||||
// Check if actor already exists
|
||||
_, err := state.GetActor(e)
|
||||
if err == nil {
|
||||
signers = append(signers, idAddress)
|
||||
continue
|
||||
}
|
||||
|
||||
st, err := cst.Put(ctx, &account.State{Address: e})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = state.SetActor(idAddress, &types.Actor{
|
||||
Code: builtin.AccountActorCodeID,
|
||||
Balance: types.NewInt(0),
|
||||
Head: st,
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("setting account from actmap: %w", err)
|
||||
}
|
||||
signers = append(signers, idAddress)
|
||||
}
|
||||
|
||||
st, err := cst.Put(ctx, &multisig.State{
|
||||
Signers: signers,
|
||||
NumApprovalsThreshold: uint64(ainfo.Threshold),
|
||||
StartEpoch: abi.ChainEpoch(ainfo.VestingStart),
|
||||
UnlockDuration: abi.ChainEpoch(ainfo.VestingDuration),
|
||||
PendingTxns: pending,
|
||||
InitialBalance: info.Balance,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = state.SetActor(ida, &types.Actor{
|
||||
Code: builtin.MultisigActorCodeID,
|
||||
Balance: info.Balance,
|
||||
Head: st,
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("setting account from actmap: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot cid.Cid, template genesis.Template, keyIDs map[address.Address]address.Address) (cid.Cid, error) {
|
||||
verifNeeds := make(map[address.Address]abi.PaddedPieceSize)
|
||||
var sum abi.PaddedPieceSize
|
||||
for _, m := range template.Miners {
|
||||
for _, s := range m.Sectors {
|
||||
amt := s.Deal.PieceSize
|
||||
verifNeeds[s.Deal.Client] += amt
|
||||
sum += amt
|
||||
}
|
||||
|
||||
nwv := func(context.Context, abi.ChainEpoch) network.Version {
|
||||
return build.NewestNetworkVersion
|
||||
}
|
||||
|
||||
verifier, err := address.NewIDAddress(80)
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
vmopt := vm.VMOpts{
|
||||
StateBase: stateroot,
|
||||
Epoch: 0,
|
||||
Rand: &fakeRand{},
|
||||
Bstore: cs.Blockstore(),
|
||||
Syscalls: mkFakedSigSyscalls(cs.VMSys()),
|
||||
CircSupplyCalc: nil,
|
||||
NtwkVersion: nwv,
|
||||
BaseFee: types.NewInt(0),
|
||||
}
|
||||
|
||||
vm, err := vm.NewVM(stateroot, 0, &fakeRand{}, cs.Blockstore(), &fakedSigSyscalls{cs.VMSys()})
|
||||
vm, err := vm.NewVM(&vmopt)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to create NewVM: %w", err)
|
||||
}
|
||||
|
||||
_, err = doExecValue(ctx, vm, builtin.VerifiedRegistryActorAddr, RootVerifierAddr, types.NewInt(0), builtin.MethodsVerifiedRegistry.AddVerifier, mustEnc(&verifreg.AddVerifierParams{
|
||||
for mi, m := range template.Miners {
|
||||
for si, s := range m.Sectors {
|
||||
if s.Deal.Provider != m.ID {
|
||||
return cid.Undef, xerrors.Errorf("Sector %d in miner %d in template had mismatch in provider and miner ID: %s != %s", si, mi, s.Deal.Provider, m.ID)
|
||||
}
|
||||
|
||||
amt := s.Deal.PieceSize
|
||||
verifNeeds[keyIDs[s.Deal.Client]] += amt
|
||||
sum += amt
|
||||
}
|
||||
}
|
||||
|
||||
verifregRoot, err := address.NewIDAddress(80)
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
verifier, err := address.NewIDAddress(81)
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
_, err = doExecValue(ctx, vm, builtin.VerifiedRegistryActorAddr, verifregRoot, types.NewInt(0), builtin.MethodsVerifiedRegistry.AddVerifier, mustEnc(&verifreg.AddVerifierParams{
|
||||
|
||||
Address: verifier,
|
||||
Allowance: abi.NewStoragePower(int64(sum)), // eh, close enough
|
||||
|
||||
}))
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to failed to create verifier: %w", err)
|
||||
return cid.Undef, xerrors.Errorf("failed to create verifier: %w", err)
|
||||
}
|
||||
|
||||
for c, amt := range verifNeeds {
|
||||
@@ -281,11 +467,16 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot ci
|
||||
}
|
||||
}
|
||||
|
||||
return vm.Flush(ctx)
|
||||
st, err := vm.Flush(ctx)
|
||||
if err != nil {
|
||||
return cid.Cid{}, xerrors.Errorf("vm flush: %w", err)
|
||||
}
|
||||
|
||||
return st, nil
|
||||
}
|
||||
|
||||
func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys runtime.Syscalls, template genesis.Template) (*GenesisBootstrap, error) {
|
||||
st, err := MakeInitialStateTree(ctx, bs, template)
|
||||
func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys vm.SyscallBuilder, template genesis.Template) (*GenesisBootstrap, error) {
|
||||
st, keyIDs, err := MakeInitialStateTree(ctx, bs, template)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("make initial state tree failed: %w", err)
|
||||
}
|
||||
@@ -299,19 +490,18 @@ func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys runtime.Sys
|
||||
cs := store.NewChainStore(bs, datastore.NewMapDatastore(), sys)
|
||||
|
||||
// Verify PreSealed Data
|
||||
stateroot, err = VerifyPreSealedData(ctx, cs, stateroot, template)
|
||||
stateroot, err = VerifyPreSealedData(ctx, cs, stateroot, template, keyIDs)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to verify presealed data: %w", err)
|
||||
}
|
||||
|
||||
stateroot, err = SetupStorageMiners(ctx, cs, stateroot, template.Miners)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("setup storage miners failed: %w", err)
|
||||
return nil, xerrors.Errorf("setup miners failed: %w", err)
|
||||
}
|
||||
|
||||
cst := cbor.NewCborStore(bs)
|
||||
|
||||
emptyroot, err := amt.FromArray(ctx, cst, nil)
|
||||
store := adt.WrapStore(ctx, cbor.NewCborStore(bs))
|
||||
emptyroot, err := adt.MakeEmptyArray(store).Root()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("amt build failed: %w", err)
|
||||
}
|
||||
@@ -330,14 +520,38 @@ func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys runtime.Sys
|
||||
|
||||
log.Infof("Empty Genesis root: %s", emptyroot)
|
||||
|
||||
tickBuf := make([]byte, 32)
|
||||
_, _ = rand.Read(tickBuf)
|
||||
genesisticket := &types.Ticket{
|
||||
VRFProof: []byte("vrf proof0000000vrf proof0000000"),
|
||||
VRFProof: tickBuf,
|
||||
}
|
||||
|
||||
filecoinGenesisCid, err := cid.Decode("bafyreiaqpwbbyjo4a42saasj36kkrpv4tsherf2e7bvezkert2a7dhonoi")
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to decode filecoin genesis block CID: %w", err)
|
||||
}
|
||||
|
||||
if !expectedCid().Equals(filecoinGenesisCid) {
|
||||
return nil, xerrors.Errorf("expectedCid != filecoinGenesisCid")
|
||||
}
|
||||
|
||||
gblk, err := getGenesisBlock()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to construct filecoin genesis block: %w", err)
|
||||
}
|
||||
|
||||
if !filecoinGenesisCid.Equals(gblk.Cid()) {
|
||||
return nil, xerrors.Errorf("filecoinGenesisCid != gblk.Cid")
|
||||
}
|
||||
|
||||
if err := bs.Put(gblk); err != nil {
|
||||
return nil, xerrors.Errorf("failed writing filecoin genesis block to blockstore: %w", err)
|
||||
}
|
||||
|
||||
b := &types.BlockHeader{
|
||||
Miner: builtin.SystemActorAddr,
|
||||
Ticket: genesisticket,
|
||||
Parents: []cid.Cid{},
|
||||
Parents: []cid.Cid{filecoinGenesisCid},
|
||||
Height: 0,
|
||||
ParentWeight: types.NewInt(0),
|
||||
ParentStateRoot: stateroot,
|
||||
@@ -353,6 +567,7 @@ func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys runtime.Sys
|
||||
Data: make([]byte, 32),
|
||||
},
|
||||
},
|
||||
ParentBaseFee: abi.NewTokenAmount(build.InitialBaseFee),
|
||||
}
|
||||
|
||||
sb, err := b.ToStorageBlock()
|
||||
|
||||
+247
-98
@@ -6,23 +6,29 @@ import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/sector-storage/ffiwrapper"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/market"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/reward"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
|
||||
"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"
|
||||
@@ -46,8 +52,35 @@ func (fss *fakedSigSyscalls) VerifySignature(signature crypto.Signature, signer
|
||||
return nil
|
||||
}
|
||||
|
||||
func mkFakedSigSyscalls(base vm.SyscallBuilder) vm.SyscallBuilder {
|
||||
return func(ctx context.Context, cstate *state.StateTree, cst cbor.IpldStore) runtime.Syscalls {
|
||||
return &fakedSigSyscalls{
|
||||
base(ctx, cstate, cst),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid, miners []genesis.Miner) (cid.Cid, error) {
|
||||
vm, err := vm.NewVM(sroot, 0, &fakeRand{}, cs.Blockstore(), &fakedSigSyscalls{cs.VMSys()})
|
||||
csc := func(context.Context, abi.ChainEpoch, *state.StateTree) (abi.TokenAmount, error) {
|
||||
return big.Zero(), nil
|
||||
}
|
||||
|
||||
nwv := func(context.Context, abi.ChainEpoch) network.Version {
|
||||
return build.NewestNetworkVersion
|
||||
}
|
||||
|
||||
vmopt := &vm.VMOpts{
|
||||
StateBase: sroot,
|
||||
Epoch: 0,
|
||||
Rand: &fakeRand{},
|
||||
Bstore: cs.Blockstore(),
|
||||
Syscalls: mkFakedSigSyscalls(cs.VMSys()),
|
||||
CircSupplyCalc: csc,
|
||||
NtwkVersion: nwv,
|
||||
BaseFee: types.NewInt(0),
|
||||
}
|
||||
|
||||
vm, err := vm.NewVM(vmopt)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to create NewVM: %w", err)
|
||||
}
|
||||
@@ -56,6 +89,14 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
return cid.Undef, xerrors.New("no genesis miners")
|
||||
}
|
||||
|
||||
minerInfos := make([]struct {
|
||||
maddr address.Address
|
||||
|
||||
presealExp abi.ChainEpoch
|
||||
|
||||
dealIDs []abi.DealID
|
||||
}, len(miners))
|
||||
|
||||
for i, m := range miners {
|
||||
// Create miner through power actor
|
||||
i := i
|
||||
@@ -66,7 +107,6 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
var maddr address.Address
|
||||
{
|
||||
constructorParams := &power.CreateMinerParams{
|
||||
Owner: m.Worker,
|
||||
@@ -90,49 +130,52 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
if ma.IDAddress != expma {
|
||||
return cid.Undef, xerrors.Errorf("miner assigned wrong address: %s != %s", ma.IDAddress, expma)
|
||||
}
|
||||
maddr = ma.IDAddress
|
||||
minerInfos[i].maddr = ma.IDAddress
|
||||
|
||||
err = vm.MutateState(ctx, minerInfos[i].maddr, func(cst cbor.IpldStore, st *miner.State) error {
|
||||
maxPeriods := miner.MaxSectorExpirationExtension / miner.WPoStProvingPeriod
|
||||
minerInfos[i].presealExp = (maxPeriods-1)*miner.WPoStProvingPeriod + st.ProvingPeriodStart - 1
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("mutating state: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Add market funds
|
||||
|
||||
{
|
||||
params := mustEnc(&maddr)
|
||||
if m.MarketBalance.GreaterThan(big.Zero()) {
|
||||
params := mustEnc(&minerInfos[i].maddr)
|
||||
_, err := doExecValue(ctx, vm, builtin.StorageMarketActorAddr, m.Worker, m.MarketBalance, builtin.MethodsMarket.AddBalance, params)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to create genesis miner: %w", err)
|
||||
}
|
||||
}
|
||||
{
|
||||
params := mustEnc(&m.Worker)
|
||||
_, err := doExecValue(ctx, vm, builtin.StorageMarketActorAddr, m.Worker, big.Zero(), builtin.MethodsMarket.AddBalance, params)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to create genesis miner: %w", err)
|
||||
return cid.Undef, xerrors.Errorf("failed to create genesis miner (add balance): %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Publish preseal deals
|
||||
|
||||
var dealIDs []abi.DealID
|
||||
{
|
||||
publish := func(params *market.PublishStorageDealsParams) error {
|
||||
fmt.Printf("publishing %d storage deals on miner %s with worker %s\n", len(params.Deals), params.Deals[0].Proposal.Provider, m.Worker)
|
||||
|
||||
ret, err := doExecValue(ctx, vm, builtin.StorageMarketActorAddr, m.Worker, big.Zero(), builtin.MethodsMarket.PublishStorageDeals, mustEnc(params))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to create genesis miner: %w", err)
|
||||
return xerrors.Errorf("failed to create genesis miner (publish deals): %w", err)
|
||||
}
|
||||
var ids market.PublishStorageDealsReturn
|
||||
if err := ids.UnmarshalCBOR(bytes.NewReader(ret)); err != nil {
|
||||
return xerrors.Errorf("unmarsahling publishStorageDeals result: %w", err)
|
||||
}
|
||||
|
||||
dealIDs = append(dealIDs, ids.IDs...)
|
||||
minerInfos[i].dealIDs = append(minerInfos[i].dealIDs, ids.IDs...)
|
||||
return nil
|
||||
}
|
||||
|
||||
params := &market.PublishStorageDealsParams{}
|
||||
for _, preseal := range m.Sectors {
|
||||
preseal.Deal.VerifiedDeal = true
|
||||
preseal.Deal.EndEpoch = minerInfos[i].presealExp
|
||||
params.Deals = append(params.Deals, market.ClientDealProposal{
|
||||
Proposal: preseal.Deal,
|
||||
ClientSignature: crypto.Signature{Type: crypto.SigTypeBLS}, // TODO: do we want to sign these? Or do we want to fake signatures for genesis setup?
|
||||
@@ -153,99 +196,137 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Commit sectors
|
||||
for pi, preseal := range m.Sectors {
|
||||
preseal := preseal
|
||||
// TODO: Maybe check seal (Can just be snark inputs, doesn't go into the genesis file)
|
||||
// adjust total network power for equal pledge per sector
|
||||
rawPow, qaPow := big.NewInt(0), big.NewInt(0)
|
||||
{
|
||||
for i, m := range miners {
|
||||
for pi := range m.Sectors {
|
||||
rawPow = types.BigAdd(rawPow, types.NewInt(uint64(m.SectorSize)))
|
||||
|
||||
// check deals, get dealWeight
|
||||
var dealWeight market.VerifyDealsOnSectorProveCommitReturn
|
||||
{
|
||||
params := &market.VerifyDealsOnSectorProveCommitParams{
|
||||
DealIDs: []abi.DealID{dealIDs[pi]},
|
||||
SectorExpiry: preseal.Deal.EndEpoch,
|
||||
}
|
||||
|
||||
ret, err := doExecValue(ctx, vm, builtin.StorageMarketActorAddr, maddr, big.Zero(), builtin.MethodsMarket.VerifyDealsOnSectorProveCommit, mustEnc(params))
|
||||
dweight, err := dealWeight(ctx, vm, minerInfos[i].maddr, []abi.DealID{minerInfos[i].dealIDs[pi]}, 0, minerInfos[i].presealExp)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to verify preseal deals miner: %w", err)
|
||||
}
|
||||
if err := dealWeight.UnmarshalCBOR(bytes.NewReader(ret)); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("unmarshaling market onProveCommit result: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// update power claims
|
||||
{
|
||||
err = vm.MutateState(ctx, builtin.StoragePowerActorAddr, func(cst cbor.IpldStore, st *power.State) error {
|
||||
weight := &power.SectorStorageWeightDesc{
|
||||
SectorSize: m.SectorSize,
|
||||
Duration: preseal.Deal.Duration(),
|
||||
DealWeight: dealWeight.DealWeight,
|
||||
VerifiedDealWeight: dealWeight.VerifiedDealWeight,
|
||||
}
|
||||
|
||||
qapower := power.QAPowerForWeight(weight)
|
||||
|
||||
err := st.AddToClaim(&state.AdtStore{cst}, maddr, types.NewInt(uint64(weight.SectorSize)), qapower)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("add to claim: %w", err)
|
||||
}
|
||||
fmt.Println("Added weight to claim: ", st.TotalRawBytePower, st.TotalQualityAdjPower)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("register power claim in power actor: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Put sectors to miner sector sets
|
||||
{
|
||||
newSectorInfo := &miner.SectorOnChainInfo{
|
||||
Info: miner.SectorPreCommitInfo{
|
||||
SealProof: preseal.ProofType,
|
||||
SectorNumber: preseal.SectorID,
|
||||
SealedCID: preseal.CommR,
|
||||
SealRandEpoch: 0,
|
||||
DealIDs: []abi.DealID{dealIDs[pi]},
|
||||
Expiration: preseal.Deal.EndEpoch,
|
||||
},
|
||||
ActivationEpoch: 0,
|
||||
DealWeight: dealWeight.DealWeight,
|
||||
VerifiedDealWeight: dealWeight.VerifiedDealWeight,
|
||||
return cid.Undef, xerrors.Errorf("getting deal weight: %w", err)
|
||||
}
|
||||
|
||||
err = vm.MutateState(ctx, maddr, func(cst cbor.IpldStore, st *miner.State) error {
|
||||
store := &state.AdtStore{cst}
|
||||
sectorWeight := miner.QAPowerForWeight(m.SectorSize, minerInfos[i].presealExp, dweight.DealWeight, dweight.VerifiedDealWeight)
|
||||
|
||||
if err = st.PutSector(store, newSectorInfo); err != nil {
|
||||
return xerrors.Errorf("failed to put sector: %v", err)
|
||||
}
|
||||
|
||||
if err := st.AddNewSectors(newSectorInfo.Info.SectorNumber); err != nil {
|
||||
return xerrors.Errorf("failed to add NewSector: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return cid.Cid{}, xerrors.Errorf("put to sset: %w", err)
|
||||
}
|
||||
qaPow = types.BigAdd(qaPow, sectorWeight)
|
||||
}
|
||||
}
|
||||
|
||||
err = vm.MutateState(ctx, builtin.StoragePowerActorAddr, func(cst cbor.IpldStore, st *power.State) error {
|
||||
st.TotalQualityAdjPower = qaPow
|
||||
st.TotalRawBytePower = rawPow
|
||||
|
||||
st.ThisEpochQualityAdjPower = qaPow
|
||||
st.ThisEpochRawBytePower = rawPow
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("mutating state: %w", err)
|
||||
}
|
||||
|
||||
err = vm.MutateState(ctx, builtin.RewardActorAddr, func(sct cbor.IpldStore, st *reward.State) error {
|
||||
*st = *reward.ConstructState(qaPow)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("mutating state: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: to avoid division by zero, we set the initial power actor power to 1, this adjusts that back down so the accounting is accurate.
|
||||
for i, m := range miners {
|
||||
// Commit sectors
|
||||
{
|
||||
for pi, preseal := range m.Sectors {
|
||||
params := &miner.SectorPreCommitInfo{
|
||||
SealProof: preseal.ProofType,
|
||||
SectorNumber: preseal.SectorID,
|
||||
SealedCID: preseal.CommR,
|
||||
SealRandEpoch: -1,
|
||||
DealIDs: []abi.DealID{minerInfos[i].dealIDs[pi]},
|
||||
Expiration: minerInfos[i].presealExp, // TODO: Allow setting externally!
|
||||
}
|
||||
|
||||
dweight, err := dealWeight(ctx, vm, minerInfos[i].maddr, params.DealIDs, 0, minerInfos[i].presealExp)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("getting deal weight: %w", err)
|
||||
}
|
||||
|
||||
sectorWeight := miner.QAPowerForWeight(m.SectorSize, minerInfos[i].presealExp, dweight.DealWeight, dweight.VerifiedDealWeight)
|
||||
|
||||
// we've added fake power for this sector above, remove it now
|
||||
err = vm.MutateState(ctx, builtin.StoragePowerActorAddr, func(cst cbor.IpldStore, st *power.State) error {
|
||||
st.TotalQualityAdjPower = types.BigSub(st.TotalQualityAdjPower, sectorWeight) //nolint:scopelint
|
||||
st.TotalRawBytePower = types.BigSub(st.TotalRawBytePower, types.NewInt(uint64(m.SectorSize)))
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("removing fake power: %w", err)
|
||||
}
|
||||
|
||||
epochReward, err := currentEpochBlockReward(ctx, vm, minerInfos[i].maddr)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("getting current epoch reward: %w", err)
|
||||
}
|
||||
|
||||
tpow, err := currentTotalPower(ctx, vm, minerInfos[i].maddr)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("getting current total power: %w", err)
|
||||
}
|
||||
|
||||
pcd := miner.PreCommitDepositForPower(epochReward.ThisEpochRewardSmoothed, tpow.QualityAdjPowerSmoothed, sectorWeight)
|
||||
|
||||
pledge := miner.InitialPledgeForPower(
|
||||
sectorWeight,
|
||||
epochReward.ThisEpochBaselinePower,
|
||||
tpow.PledgeCollateral,
|
||||
epochReward.ThisEpochRewardSmoothed,
|
||||
tpow.QualityAdjPowerSmoothed,
|
||||
circSupply(ctx, vm, minerInfos[i].maddr),
|
||||
)
|
||||
|
||||
pledge = big.Add(pcd, pledge)
|
||||
|
||||
fmt.Println(types.FIL(pledge))
|
||||
_, err = doExecValue(ctx, vm, minerInfos[i].maddr, m.Worker, pledge, builtin.MethodsMiner.PreCommitSector, mustEnc(params))
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to confirm presealed sectors: %w", err)
|
||||
}
|
||||
|
||||
// Commit one-by-one, otherwise pledge math tends to explode
|
||||
confirmParams := &builtin.ConfirmSectorProofsParams{
|
||||
Sectors: []abi.SectorNumber{preseal.SectorID},
|
||||
}
|
||||
|
||||
_, err = doExecValue(ctx, vm, minerInfos[i].maddr, builtin.StoragePowerActorAddr, big.Zero(), builtin.MethodsMiner.ConfirmSectorProofsValid, mustEnc(confirmParams))
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to confirm presealed sectors: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sanity-check total network power
|
||||
err = vm.MutateState(ctx, builtin.StoragePowerActorAddr, func(cst cbor.IpldStore, st *power.State) error {
|
||||
st.TotalQualityAdjPower = big.Sub(st.TotalQualityAdjPower, big.NewInt(1))
|
||||
if !st.TotalRawBytePower.Equals(rawPow) {
|
||||
return xerrors.Errorf("st.TotalRawBytePower doesn't match previously calculated rawPow")
|
||||
}
|
||||
|
||||
if !st.TotalQualityAdjPower.Equals(qaPow) {
|
||||
return xerrors.Errorf("st.TotalQualityAdjPower doesn't match previously calculated qaPow")
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("mutating state: %w", err)
|
||||
}
|
||||
|
||||
// TODO: Should we re-ConstructState for the reward actor using rawPow as currRealizedPower here?
|
||||
|
||||
c, err := vm.Flush(ctx)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("flushing vm: %w", err)
|
||||
@@ -256,8 +337,76 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
// TODO: copied from actors test harness, deduplicate or remove from here
|
||||
type fakeRand struct{}
|
||||
|
||||
func (fr *fakeRand) GetRandomness(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
func (fr *fakeRand) GetChainRandomness(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
out := make([]byte, 32)
|
||||
_, _ = rand.New(rand.NewSource(int64(randEpoch))).Read(out)
|
||||
_, _ = rand.New(rand.NewSource(int64(randEpoch * 1000))).Read(out) //nolint
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (fr *fakeRand) GetBeaconRandomness(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
out := make([]byte, 32)
|
||||
_, _ = rand.New(rand.NewSource(int64(randEpoch))).Read(out) //nolint
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func currentTotalPower(ctx context.Context, vm *vm.VM, maddr address.Address) (*power.CurrentTotalPowerReturn, error) {
|
||||
pwret, err := doExecValue(ctx, vm, builtin.StoragePowerActorAddr, maddr, big.Zero(), builtin.MethodsPower.CurrentTotalPower, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var pwr power.CurrentTotalPowerReturn
|
||||
if err := pwr.UnmarshalCBOR(bytes.NewReader(pwret)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &pwr, nil
|
||||
}
|
||||
|
||||
func dealWeight(ctx context.Context, vm *vm.VM, maddr address.Address, dealIDs []abi.DealID, sectorStart, sectorExpiry abi.ChainEpoch) (market.VerifyDealsForActivationReturn, error) {
|
||||
params := &market.VerifyDealsForActivationParams{
|
||||
DealIDs: dealIDs,
|
||||
SectorStart: sectorStart,
|
||||
SectorExpiry: sectorExpiry,
|
||||
}
|
||||
|
||||
var dealWeights market.VerifyDealsForActivationReturn
|
||||
ret, err := doExecValue(ctx, vm,
|
||||
builtin.StorageMarketActorAddr,
|
||||
maddr,
|
||||
abi.NewTokenAmount(0),
|
||||
builtin.MethodsMarket.VerifyDealsForActivation,
|
||||
mustEnc(params),
|
||||
)
|
||||
if err != nil {
|
||||
return market.VerifyDealsForActivationReturn{}, err
|
||||
}
|
||||
if err := dealWeights.UnmarshalCBOR(bytes.NewReader(ret)); err != nil {
|
||||
return market.VerifyDealsForActivationReturn{}, err
|
||||
}
|
||||
|
||||
return dealWeights, nil
|
||||
}
|
||||
|
||||
func currentEpochBlockReward(ctx context.Context, vm *vm.VM, maddr address.Address) (*reward.ThisEpochRewardReturn, error) {
|
||||
rwret, err := doExecValue(ctx, vm, builtin.RewardActorAddr, maddr, big.Zero(), builtin.MethodsReward.ThisEpochReward, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var epochReward reward.ThisEpochRewardReturn
|
||||
if err := epochReward.UnmarshalCBOR(bytes.NewReader(rwret)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &epochReward, nil
|
||||
}
|
||||
|
||||
func circSupply(ctx context.Context, vmi *vm.VM, maddr address.Address) abi.TokenAmount {
|
||||
unsafeVM := &vm.UnsafeVM{VM: vmi}
|
||||
rt := unsafeVM.MakeRuntime(ctx, &types.Message{
|
||||
GasLimit: 1_000_000_000,
|
||||
From: maddr,
|
||||
}, maddr, 0, 0, 0)
|
||||
|
||||
return rt.TotalFilCircSupply()
|
||||
}
|
||||
|
||||
@@ -2,12 +2,14 @@ package genesis
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/system"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
bstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
bstore "github.com/filecoin-project/lotus/lib/blockstore"
|
||||
)
|
||||
|
||||
func SetupSystemActor(bs bstore.Blockstore) (*types.Actor, error) {
|
||||
|
||||
@@ -5,64 +5,133 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||
"github.com/ipfs/go-hamt-ipld"
|
||||
bstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/genesis"
|
||||
bstore "github.com/filecoin-project/lotus/lib/blockstore"
|
||||
)
|
||||
|
||||
func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesis.Actor) (*types.Actor, error) {
|
||||
func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesis.Actor, rootVerifier genesis.Actor) (int64, *types.Actor, map[address.Address]address.Address, error) {
|
||||
if len(initialActors) > MaxAccounts {
|
||||
return nil, xerrors.New("too many initial actors")
|
||||
return 0, nil, nil, xerrors.New("too many initial actors")
|
||||
}
|
||||
|
||||
var ias init_.State
|
||||
ias.NextID = MinerStart
|
||||
ias.NetworkName = netname
|
||||
|
||||
cst := cbor.NewCborStore(bs)
|
||||
amap := hamt.NewNode(cst, hamt.UseTreeBitWidth(5)) // TODO: use spec adt map
|
||||
store := adt.WrapStore(context.TODO(), cbor.NewCborStore(bs))
|
||||
amap := adt.MakeEmptyMap(store)
|
||||
|
||||
keyToId := map[address.Address]address.Address{}
|
||||
counter := int64(AccountStart)
|
||||
|
||||
for _, a := range initialActors {
|
||||
if a.Type == genesis.TMultisig {
|
||||
var ainfo genesis.MultisigMeta
|
||||
if err := json.Unmarshal(a.Meta, &ainfo); err != nil {
|
||||
return 0, nil, nil, xerrors.Errorf("unmarshaling account meta: %w", err)
|
||||
}
|
||||
for _, e := range ainfo.Signers {
|
||||
|
||||
if _, ok := keyToId[e]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Printf("init set %s t0%d\n", e, counter)
|
||||
|
||||
value := cbg.CborInt(counter)
|
||||
if err := amap.Put(adt.AddrKey(e), &value); err != nil {
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
counter = counter + 1
|
||||
var err error
|
||||
keyToId[e], err = address.NewIDAddress(uint64(value))
|
||||
if err != nil {
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
|
||||
}
|
||||
// Need to add actors for all multisigs too
|
||||
continue
|
||||
}
|
||||
|
||||
for i, a := range initialActors {
|
||||
if a.Type != genesis.TAccount {
|
||||
return nil, xerrors.Errorf("unsupported account type: %s", a.Type) // TODO: Support msig (skip here)
|
||||
return 0, nil, nil, xerrors.Errorf("unsupported account type: %s", a.Type)
|
||||
}
|
||||
|
||||
var ainfo genesis.AccountMeta
|
||||
if err := json.Unmarshal(a.Meta, &ainfo); err != nil {
|
||||
return nil, xerrors.Errorf("unmarshaling account meta: %w", err)
|
||||
return 0, nil, nil, xerrors.Errorf("unmarshaling account meta: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("init set %s t0%d\n", ainfo.Owner, AccountStart+uint64(i))
|
||||
fmt.Printf("init set %s t0%d\n", ainfo.Owner, counter)
|
||||
|
||||
if err := amap.Set(context.TODO(), string(ainfo.Owner.Bytes()), AccountStart+uint64(i)); err != nil {
|
||||
return nil, err
|
||||
value := cbg.CborInt(counter)
|
||||
if err := amap.Put(adt.AddrKey(ainfo.Owner), &value); err != nil {
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
counter = counter + 1
|
||||
|
||||
var err error
|
||||
keyToId[ainfo.Owner], err = address.NewIDAddress(uint64(value))
|
||||
if err != nil {
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if err := amap.Set(context.TODO(), string(RootVerifierAddr.Bytes()), 80); err != nil {
|
||||
return nil, err
|
||||
if rootVerifier.Type == genesis.TAccount {
|
||||
var ainfo genesis.AccountMeta
|
||||
if err := json.Unmarshal(rootVerifier.Meta, &ainfo); err != nil {
|
||||
return 0, nil, nil, xerrors.Errorf("unmarshaling account meta: %w", err)
|
||||
}
|
||||
value := cbg.CborInt(80)
|
||||
if err := amap.Put(adt.AddrKey(ainfo.Owner), &value); err != nil {
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
} else if rootVerifier.Type == genesis.TMultisig {
|
||||
var ainfo genesis.MultisigMeta
|
||||
if err := json.Unmarshal(rootVerifier.Meta, &ainfo); err != nil {
|
||||
return 0, nil, nil, xerrors.Errorf("unmarshaling account meta: %w", err)
|
||||
}
|
||||
for _, e := range ainfo.Signers {
|
||||
if _, ok := keyToId[e]; ok {
|
||||
continue
|
||||
}
|
||||
fmt.Printf("init set %s t0%d\n", e, counter)
|
||||
|
||||
value := cbg.CborInt(counter)
|
||||
if err := amap.Put(adt.AddrKey(e), &value); err != nil {
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
counter = counter + 1
|
||||
var err error
|
||||
keyToId[e], err = address.NewIDAddress(uint64(value))
|
||||
if err != nil {
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if err := amap.Flush(context.TODO()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
amapcid, err := cst.Put(context.TODO(), amap)
|
||||
amapaddr, err := amap.Root()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
ias.AddressMap = amapaddr
|
||||
|
||||
ias.AddressMap = amapcid
|
||||
|
||||
statecid, err := cst.Put(context.TODO(), &ias)
|
||||
statecid, err := store.Put(store.Context(), &ias)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
|
||||
act := &types.Actor{
|
||||
@@ -70,5 +139,5 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi
|
||||
Head: statecid,
|
||||
}
|
||||
|
||||
return act, nil
|
||||
return counter, act, keyToId, nil
|
||||
}
|
||||
|
||||
@@ -3,19 +3,21 @@ package genesis
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/reward"
|
||||
bstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
bstore "github.com/filecoin-project/lotus/lib/blockstore"
|
||||
)
|
||||
|
||||
func SetupRewardActor(bs bstore.Blockstore) (*types.Actor, error) {
|
||||
func SetupRewardActor(bs bstore.Blockstore, qaPower big.Int) (*types.Actor, error) {
|
||||
cst := cbor.NewCborStore(bs)
|
||||
|
||||
st := reward.ConstructState()
|
||||
st.LastPerEpochReward = types.FromFil(100)
|
||||
st := reward.ConstructState(qaPower)
|
||||
|
||||
hcid, err := cst.Put(context.TODO(), st)
|
||||
if err != nil {
|
||||
|
||||
@@ -5,10 +5,10 @@ import (
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/cron"
|
||||
bstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
bstore "github.com/filecoin-project/lotus/lib/blockstore"
|
||||
)
|
||||
|
||||
func SetupCronActor(bs bstore.Blockstore) (*types.Actor, error) {
|
||||
|
||||
@@ -2,38 +2,37 @@ package genesis
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
"github.com/ipfs/go-hamt-ipld"
|
||||
bstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
bstore "github.com/filecoin-project/lotus/lib/blockstore"
|
||||
)
|
||||
|
||||
func SetupStoragePowerActor(bs bstore.Blockstore) (*types.Actor, error) {
|
||||
ctx := context.TODO()
|
||||
cst := cbor.NewCborStore(bs)
|
||||
nd := hamt.NewNode(cst, hamt.UseTreeBitWidth(5))
|
||||
emptyhamt, err := cst.Put(ctx, nd)
|
||||
store := adt.WrapStore(context.TODO(), cbor.NewCborStore(bs))
|
||||
emptyMap, err := adt.MakeEmptyMap(store).Root()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sms := &power.State{
|
||||
TotalRawBytePower: big.NewInt(0),
|
||||
TotalQualityAdjPower: big.NewInt(1), // TODO: has to be 1 initially to avoid div by zero. Kinda annoying, should find a way to fix
|
||||
TotalPledgeCollateral: big.NewInt(0),
|
||||
MinerCount: 0,
|
||||
CronEventQueue: emptyhamt,
|
||||
LastEpochTick: 0,
|
||||
Claims: emptyhamt,
|
||||
NumMinersMeetingMinPower: 0,
|
||||
multiMap, err := adt.AsMultimap(store, emptyMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stcid, err := cst.Put(ctx, sms)
|
||||
emptyMultiMap, err := multiMap.Root()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sms := power.ConstructState(emptyMap, emptyMultiMap)
|
||||
|
||||
stcid, err := store.Put(store.Context(), sms)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -2,32 +2,31 @@ package genesis
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/ipfs/go-hamt-ipld"
|
||||
|
||||
"github.com/filecoin-project/go-amt-ipld/v2"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/market"
|
||||
bstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
bstore "github.com/filecoin-project/lotus/lib/blockstore"
|
||||
)
|
||||
|
||||
func SetupStorageMarketActor(bs bstore.Blockstore) (*types.Actor, error) {
|
||||
cst := cbor.NewCborStore(bs)
|
||||
store := adt.WrapStore(context.TODO(), cbor.NewCborStore(bs))
|
||||
|
||||
a, err := amt.NewAMT(cst).Flush(context.TODO())
|
||||
a, err := adt.MakeEmptyArray(store).Root()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h, err := cst.Put(context.TODO(), hamt.NewNode(cst, hamt.UseTreeBitWidth(5)))
|
||||
h, err := adt.MakeEmptyMap(store).Root()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sms := market.ConstructState(a, h, h)
|
||||
|
||||
stcid, err := cst.Put(context.TODO(), sms)
|
||||
stcid, err := store.Put(store.Context(), sms)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -4,27 +4,19 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/ipfs/go-hamt-ipld"
|
||||
bstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
bstore "github.com/filecoin-project/lotus/lib/blockstore"
|
||||
)
|
||||
|
||||
var RootVerifierAddr address.Address
|
||||
|
||||
var RootVerifierID address.Address
|
||||
|
||||
func init() {
|
||||
k, err := address.NewFromString("t3qfoulel6fy6gn3hjmbhpdpf6fs5aqjb5fkurhtwvgssizq4jey5nw4ptq5up6h7jk7frdvvobv52qzmgjinq")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
RootVerifierAddr = k
|
||||
|
||||
idk, err := address.NewFromString("t080")
|
||||
if err != nil {
|
||||
@@ -35,16 +27,16 @@ func init() {
|
||||
}
|
||||
|
||||
func SetupVerifiedRegistryActor(bs bstore.Blockstore) (*types.Actor, error) {
|
||||
cst := cbor.NewCborStore(bs)
|
||||
store := adt.WrapStore(context.TODO(), cbor.NewCborStore(bs))
|
||||
|
||||
h, err := cst.Put(context.TODO(), hamt.NewNode(cst, hamt.UseTreeBitWidth(5)))
|
||||
h, err := adt.MakeEmptyMap(store).Root()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sms := verifreg.ConstructState(h, RootVerifierID)
|
||||
|
||||
stcid, err := cst.Put(context.TODO(), sms)
|
||||
stcid, err := store.Put(store.Context(), sms)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
@@ -21,14 +21,10 @@ func mustEnc(i cbg.CBORMarshaler) []byte {
|
||||
return enc
|
||||
}
|
||||
|
||||
func doExec(ctx context.Context, vm *vm.VM, to, from address.Address, method abi.MethodNum, params []byte) ([]byte, error) {
|
||||
return doExecValue(ctx, vm, to, from, types.NewInt(0), method, params)
|
||||
}
|
||||
|
||||
func doExecValue(ctx context.Context, vm *vm.VM, to, from address.Address, value types.BigInt, method abi.MethodNum, params []byte) ([]byte, error) {
|
||||
act, err := vm.StateTree().GetActor(from)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("doExec failed to get from actor: %w", err)
|
||||
return nil, xerrors.Errorf("doExec failed to get from actor (%s): %w", from, err)
|
||||
}
|
||||
|
||||
ret, err := vm.ApplyImplicitMessage(ctx, &types.Message{
|
||||
@@ -37,7 +33,6 @@ func doExecValue(ctx context.Context, vm *vm.VM, to, from address.Address, value
|
||||
Method: method,
|
||||
Params: params,
|
||||
GasLimit: 1_000_000_000_000_000,
|
||||
GasPrice: types.NewInt(0),
|
||||
Value: value,
|
||||
Nonce: act.Nonce,
|
||||
})
|
||||
|
||||
+37
-22
@@ -3,9 +3,8 @@ package gen
|
||||
import (
|
||||
"context"
|
||||
|
||||
bls "github.com/filecoin-project/filecoin-ffi"
|
||||
amt "github.com/filecoin-project/go-amt-ipld/v2"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
cid "github.com/ipfs/go-cid"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
@@ -17,6 +16,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
"github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
)
|
||||
|
||||
func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wallet, bt *api.BlockTemplate) (*types.FullBlock, error) {
|
||||
@@ -78,17 +78,17 @@ func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wal
|
||||
}
|
||||
}
|
||||
|
||||
bs := cbor.NewCborStore(sm.ChainStore().Blockstore())
|
||||
blsmsgroot, err := amt.FromArray(ctx, bs, toIfArr(blsMsgCids))
|
||||
store := sm.ChainStore().Store(ctx)
|
||||
blsmsgroot, err := toArray(store, blsMsgCids)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("building bls amt: %w", err)
|
||||
}
|
||||
secpkmsgroot, err := amt.FromArray(ctx, bs, toIfArr(secpkMsgCids))
|
||||
secpkmsgroot, err := toArray(store, secpkMsgCids)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("building secpk amt: %w", err)
|
||||
}
|
||||
|
||||
mmcid, err := bs.Put(ctx, &types.MsgMeta{
|
||||
mmcid, err := store.Put(store.Context(), &types.MsgMeta{
|
||||
BlsMessages: blsmsgroot,
|
||||
SecpkMessages: secpkmsgroot,
|
||||
})
|
||||
@@ -109,6 +109,12 @@ func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wal
|
||||
}
|
||||
next.ParentWeight = pweight
|
||||
|
||||
baseFee, err := sm.ChainStore().ComputeBaseFee(ctx, pts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("computing base fee: %w", err)
|
||||
}
|
||||
next.ParentBaseFee = baseFee
|
||||
|
||||
cst := cbor.NewCborStore(sm.ChainStore().Blockstore())
|
||||
tree, err := state.LoadStateTree(cst, st)
|
||||
if err != nil {
|
||||
@@ -142,36 +148,45 @@ func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wal
|
||||
}
|
||||
|
||||
func aggregateSignatures(sigs []crypto.Signature) (*crypto.Signature, error) {
|
||||
var blsSigs []bls.Signature
|
||||
for _, s := range sigs {
|
||||
var bsig bls.Signature
|
||||
copy(bsig[:], s.Data)
|
||||
blsSigs = append(blsSigs, bsig)
|
||||
sigsS := make([][]byte, len(sigs))
|
||||
for i := 0; i < len(sigs); i++ {
|
||||
sigsS[i] = sigs[i].Data
|
||||
}
|
||||
|
||||
aggSig := bls.Aggregate(blsSigs)
|
||||
if aggSig == nil {
|
||||
aggregator := new(bls.AggregateSignature).AggregateCompressed(sigsS)
|
||||
if aggregator == nil {
|
||||
if len(sigs) > 0 {
|
||||
return nil, xerrors.Errorf("bls.Aggregate returned nil with %d signatures", len(sigs))
|
||||
}
|
||||
|
||||
// Note: for blst this condition should not happen - nil should not
|
||||
// be returned
|
||||
return &crypto.Signature{
|
||||
Type: crypto.SigTypeBLS,
|
||||
Data: new(bls.Signature)[:],
|
||||
Data: new(bls.Signature).Compress(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
aggSigAff := aggregator.ToAffine()
|
||||
if aggSigAff == nil {
|
||||
return &crypto.Signature{
|
||||
Type: crypto.SigTypeBLS,
|
||||
Data: new(bls.Signature).Compress(),
|
||||
}, nil
|
||||
}
|
||||
aggSig := aggSigAff.Compress()
|
||||
return &crypto.Signature{
|
||||
Type: crypto.SigTypeBLS,
|
||||
Data: aggSig[:],
|
||||
Data: aggSig,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func toIfArr(cids []cid.Cid) []cbg.CBORMarshaler {
|
||||
out := make([]cbg.CBORMarshaler, 0, len(cids))
|
||||
for _, c := range cids {
|
||||
func toArray(store adt.Store, cids []cid.Cid) (cid.Cid, error) {
|
||||
arr := adt.MakeEmptyArray(store)
|
||||
for i, c := range cids {
|
||||
oc := cbg.CborCid(c)
|
||||
out = append(out, &oc)
|
||||
if err := arr.Set(uint64(i), &oc); err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
}
|
||||
return out
|
||||
return arr.Root()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
package slashfilter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
ds "github.com/ipfs/go-datastore"
|
||||
"github.com/ipfs/go-datastore/namespace"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
type SlashFilter struct {
|
||||
byEpoch ds.Datastore // double-fork mining faults, parent-grinding fault
|
||||
byParents ds.Datastore // time-offset mining faults
|
||||
}
|
||||
|
||||
func New(dstore ds.Batching) *SlashFilter {
|
||||
return &SlashFilter{
|
||||
byEpoch: namespace.Wrap(dstore, ds.NewKey("/slashfilter/epoch")),
|
||||
byParents: namespace.Wrap(dstore, ds.NewKey("/slashfilter/parents")),
|
||||
}
|
||||
}
|
||||
|
||||
func (f *SlashFilter) MinedBlock(bh *types.BlockHeader, parentEpoch abi.ChainEpoch) error {
|
||||
epochKey := ds.NewKey(fmt.Sprintf("/%s/%d", bh.Miner, bh.Height))
|
||||
{
|
||||
// double-fork mining (2 blocks at one epoch)
|
||||
if err := checkFault(f.byEpoch, epochKey, bh, "double-fork mining faults"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
parentsKey := ds.NewKey(fmt.Sprintf("/%s/%x", bh.Miner, types.NewTipSetKey(bh.Parents...).Bytes()))
|
||||
{
|
||||
// time-offset mining faults (2 blocks with the same parents)
|
||||
if err := checkFault(f.byParents, parentsKey, bh, "time-offset mining faults"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// parent-grinding fault (didn't mine on top of our own block)
|
||||
|
||||
// First check if we have mined a block on the parent epoch
|
||||
parentEpochKey := ds.NewKey(fmt.Sprintf("/%s/%d", bh.Miner, parentEpoch))
|
||||
have, err := f.byEpoch.Has(parentEpochKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if have {
|
||||
// If we had, make sure it's in our parent tipset
|
||||
cidb, err := f.byEpoch.Get(parentEpochKey)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting other block cid: %w", err)
|
||||
}
|
||||
|
||||
_, parent, err := cid.CidFromBytes(cidb)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var found bool
|
||||
for _, c := range bh.Parents {
|
||||
if c.Equals(parent) {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
return xerrors.Errorf("produced block would trigger 'parent-grinding fault' consensus fault; miner: %s; bh: %s, expected parent: %s", bh.Miner, bh.Cid(), parent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := f.byParents.Put(parentsKey, bh.Cid().Bytes()); err != nil {
|
||||
return xerrors.Errorf("putting byEpoch entry: %w", err)
|
||||
}
|
||||
|
||||
if err := f.byEpoch.Put(epochKey, bh.Cid().Bytes()); err != nil {
|
||||
return xerrors.Errorf("putting byEpoch entry: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkFault(t ds.Datastore, key ds.Key, bh *types.BlockHeader, faultType string) error {
|
||||
fault, err := t.Has(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if fault {
|
||||
cidb, err := t.Get(key)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting other block cid: %w", err)
|
||||
}
|
||||
|
||||
_, other, err := cid.CidFromBytes(cidb)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return xerrors.Errorf("produced block would trigger '%s' consensus fault; miner: %s; bh: %s, other: %s", faultType, bh.Miner, bh.Cid(), other)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
+119
-36
@@ -4,76 +4,159 @@ import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"go.uber.org/fx"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/ipfs/go-cid"
|
||||
logging "github.com/ipfs/go-log"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"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/node/impl/full"
|
||||
)
|
||||
|
||||
var log = logging.Logger("market_adapter")
|
||||
|
||||
type FundMgr struct {
|
||||
sm *stmgr.StateManager
|
||||
mpool full.MpoolAPI
|
||||
// API is the dependencies need to run a fund manager
|
||||
type API struct {
|
||||
fx.In
|
||||
|
||||
lk sync.Mutex
|
||||
full.ChainAPI
|
||||
full.StateAPI
|
||||
full.MpoolAPI
|
||||
}
|
||||
|
||||
// FundMgr monitors available balances and adds funds when EnsureAvailable is called
|
||||
type FundMgr struct {
|
||||
api fundMgrAPI
|
||||
|
||||
lk sync.RWMutex
|
||||
available map[address.Address]types.BigInt
|
||||
}
|
||||
|
||||
func NewFundMgr(sm *stmgr.StateManager, mpool full.MpoolAPI) *FundMgr {
|
||||
return &FundMgr{
|
||||
sm: sm,
|
||||
mpool: mpool,
|
||||
// StartFundManager creates a new fund manager and sets up event hooks to manage state changes
|
||||
func StartFundManager(lc fx.Lifecycle, api API) *FundMgr {
|
||||
fm := newFundMgr(&api)
|
||||
lc.Append(fx.Hook{
|
||||
OnStart: func(ctx context.Context) error {
|
||||
ev := events.NewEvents(ctx, &api)
|
||||
preds := state.NewStatePredicates(&api)
|
||||
dealDiffFn := preds.OnStorageMarketActorChanged(preds.OnBalanceChanged(preds.AvailableBalanceChangedForAddresses(fm.getAddresses)))
|
||||
match := func(oldTs, newTs *types.TipSet) (bool, events.StateChange, error) {
|
||||
return dealDiffFn(ctx, oldTs.Key(), newTs.Key())
|
||||
}
|
||||
return ev.StateChanged(fm.checkFunc, fm.stateChanged, fm.revert, 0, events.NoTimeout, match)
|
||||
},
|
||||
})
|
||||
return fm
|
||||
}
|
||||
|
||||
type fundMgrAPI interface {
|
||||
StateMarketBalance(context.Context, address.Address, types.TipSetKey) (api.MarketBalance, error)
|
||||
MpoolPushMessage(context.Context, *types.Message, *api.MessageSendSpec) (*types.SignedMessage, error)
|
||||
StateLookupID(context.Context, address.Address, types.TipSetKey) (address.Address, error)
|
||||
}
|
||||
|
||||
func newFundMgr(api fundMgrAPI) *FundMgr {
|
||||
return &FundMgr{
|
||||
api: api,
|
||||
available: map[address.Address]types.BigInt{},
|
||||
}
|
||||
}
|
||||
|
||||
func (fm *FundMgr) EnsureAvailable(ctx context.Context, addr, wallet address.Address, amt types.BigInt) (cid.Cid, error) {
|
||||
fm.lk.Lock()
|
||||
avail, ok := fm.available[addr]
|
||||
// checkFunc tells the events api to simply proceed (we always want to watch)
|
||||
func (fm *FundMgr) checkFunc(ts *types.TipSet) (done bool, more bool, err error) {
|
||||
return false, true, nil
|
||||
}
|
||||
|
||||
// revert handles reverts to balances
|
||||
func (fm *FundMgr) revert(ctx context.Context, ts *types.TipSet) error {
|
||||
// TODO: Is it ok to just ignore this?
|
||||
log.Warn("balance change reverted; TODO: actually handle this!")
|
||||
return nil
|
||||
}
|
||||
|
||||
// stateChanged handles balance changes monitored on the chain from one tipset to the next
|
||||
func (fm *FundMgr) stateChanged(ts *types.TipSet, ts2 *types.TipSet, states events.StateChange, h abi.ChainEpoch) (more bool, err error) {
|
||||
changedBalances, ok := states.(state.ChangedBalances)
|
||||
if !ok {
|
||||
bal, err := fm.sm.MarketBalance(ctx, addr, nil)
|
||||
if err != nil {
|
||||
fm.lk.Unlock()
|
||||
return cid.Undef, err
|
||||
panic("Expected state.ChangedBalances")
|
||||
}
|
||||
// overwrite our in memory cache with new values from chain (chain is canonical)
|
||||
fm.lk.Lock()
|
||||
for addr, balanceChange := range changedBalances {
|
||||
if fm.available[addr].Int != nil {
|
||||
log.Infof("State balance change recorded, prev: %s, new: %s", fm.available[addr].String(), balanceChange.To.String())
|
||||
}
|
||||
|
||||
avail = types.BigSub(bal.Escrow, bal.Locked)
|
||||
fm.available[addr] = balanceChange.To
|
||||
}
|
||||
fm.lk.Unlock()
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (fm *FundMgr) getAddresses() []address.Address {
|
||||
fm.lk.RLock()
|
||||
defer fm.lk.RUnlock()
|
||||
addrs := make([]address.Address, 0, len(fm.available))
|
||||
for addr := range fm.available {
|
||||
addrs = append(addrs, addr)
|
||||
}
|
||||
return addrs
|
||||
}
|
||||
|
||||
// EnsureAvailable looks at the available balance in escrow for a given
|
||||
// address, and if less than the passed in amount, adds the difference
|
||||
func (fm *FundMgr) EnsureAvailable(ctx context.Context, addr, wallet address.Address, amt types.BigInt) (cid.Cid, error) {
|
||||
idAddr, err := fm.api.StateLookupID(ctx, addr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
fm.lk.Lock()
|
||||
bal, err := fm.api.StateMarketBalance(ctx, addr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
fm.lk.Unlock()
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
toAdd := types.NewInt(0)
|
||||
avail = types.BigSub(avail, amt)
|
||||
if avail.LessThan(types.NewInt(0)) {
|
||||
// TODO: some rules around adding more to avoid doing stuff on-chain
|
||||
// all the time
|
||||
toAdd = types.BigSub(toAdd, avail)
|
||||
avail = types.NewInt(0)
|
||||
}
|
||||
fm.available[addr] = avail
|
||||
stateAvail := types.BigSub(bal.Escrow, bal.Locked)
|
||||
|
||||
avail, ok := fm.available[idAddr]
|
||||
if !ok {
|
||||
avail = stateAvail
|
||||
}
|
||||
|
||||
toAdd := types.BigSub(amt, avail)
|
||||
if toAdd.LessThan(types.NewInt(0)) {
|
||||
toAdd = types.NewInt(0)
|
||||
}
|
||||
fm.available[idAddr] = big.Add(avail, toAdd)
|
||||
fm.lk.Unlock()
|
||||
|
||||
var err error
|
||||
log.Infof("Funds operation w/ Expected Balance: %s, In State: %s, Requested: %s, Adding: %s", avail.String(), stateAvail.String(), amt.String(), toAdd.String())
|
||||
|
||||
if toAdd.LessThanEqual(big.Zero()) {
|
||||
return cid.Undef, nil
|
||||
}
|
||||
|
||||
params, err := actors.SerializeParams(&addr)
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
smsg, err := fm.mpool.MpoolPushMessage(ctx, &types.Message{
|
||||
To: builtin.StorageMarketActorAddr,
|
||||
From: wallet,
|
||||
Value: toAdd,
|
||||
GasPrice: types.NewInt(0),
|
||||
GasLimit: 1000000,
|
||||
Method: builtin.MethodsMarket.AddBalance,
|
||||
Params: params,
|
||||
})
|
||||
smsg, err := fm.api.MpoolPushMessage(ctx, &types.Message{
|
||||
To: builtin.StorageMarketActorAddr,
|
||||
From: wallet,
|
||||
Value: toAdd,
|
||||
Method: builtin.MethodsMarket.AddBalance,
|
||||
Params: params,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
package market
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"math/rand"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"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/specs-actors/actors/builtin"
|
||||
tutils "github.com/filecoin-project/specs-actors/support/testing"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
type fakeAPI struct {
|
||||
returnedBalance api.MarketBalance
|
||||
returnedBalanceErr error
|
||||
signature crypto.Signature
|
||||
receivedMessage *types.Message
|
||||
pushMessageErr error
|
||||
lookupIDErr error
|
||||
}
|
||||
|
||||
func (fapi *fakeAPI) StateLookupID(_ context.Context, addr address.Address, _ types.TipSetKey) (address.Address, error) {
|
||||
return addr, fapi.lookupIDErr
|
||||
}
|
||||
func (fapi *fakeAPI) StateMarketBalance(context.Context, address.Address, types.TipSetKey) (api.MarketBalance, error) {
|
||||
return fapi.returnedBalance, fapi.returnedBalanceErr
|
||||
}
|
||||
|
||||
func (fapi *fakeAPI) MpoolPushMessage(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec) (*types.SignedMessage, error) {
|
||||
fapi.receivedMessage = msg
|
||||
return &types.SignedMessage{
|
||||
Message: *msg,
|
||||
Signature: fapi.signature,
|
||||
}, fapi.pushMessageErr
|
||||
}
|
||||
|
||||
func addFundsMsg(toAdd abi.TokenAmount, addr address.Address, wallet address.Address) *types.Message {
|
||||
params, _ := actors.SerializeParams(&addr)
|
||||
return &types.Message{
|
||||
To: builtin.StorageMarketActorAddr,
|
||||
From: wallet,
|
||||
Value: toAdd,
|
||||
Method: builtin.MethodsMarket.AddBalance,
|
||||
Params: params,
|
||||
}
|
||||
}
|
||||
|
||||
type expectedResult struct {
|
||||
addAmt abi.TokenAmount
|
||||
shouldAdd bool
|
||||
err error
|
||||
}
|
||||
|
||||
func TestAddFunds(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
testCases := map[string]struct {
|
||||
returnedBalanceErr error
|
||||
returnedBalance api.MarketBalance
|
||||
addAmounts []abi.TokenAmount
|
||||
pushMessageErr error
|
||||
expectedResults []expectedResult
|
||||
lookupIDErr error
|
||||
}{
|
||||
"succeeds, trivial case": {
|
||||
returnedBalance: api.MarketBalance{Escrow: abi.NewTokenAmount(0), Locked: abi.NewTokenAmount(0)},
|
||||
addAmounts: []abi.TokenAmount{abi.NewTokenAmount(100)},
|
||||
expectedResults: []expectedResult{
|
||||
{
|
||||
addAmt: abi.NewTokenAmount(100),
|
||||
shouldAdd: true,
|
||||
err: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
"succeeds, money already present": {
|
||||
returnedBalance: api.MarketBalance{Escrow: abi.NewTokenAmount(150), Locked: abi.NewTokenAmount(50)},
|
||||
addAmounts: []abi.TokenAmount{abi.NewTokenAmount(100)},
|
||||
expectedResults: []expectedResult{
|
||||
{
|
||||
shouldAdd: false,
|
||||
err: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
"succeeds, multiple adds": {
|
||||
returnedBalance: api.MarketBalance{Escrow: abi.NewTokenAmount(150), Locked: abi.NewTokenAmount(50)},
|
||||
addAmounts: []abi.TokenAmount{abi.NewTokenAmount(100), abi.NewTokenAmount(200), abi.NewTokenAmount(250), abi.NewTokenAmount(250)},
|
||||
expectedResults: []expectedResult{
|
||||
{
|
||||
shouldAdd: false,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
addAmt: abi.NewTokenAmount(100),
|
||||
shouldAdd: true,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
addAmt: abi.NewTokenAmount(50),
|
||||
shouldAdd: true,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
shouldAdd: false,
|
||||
err: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
"error on market balance": {
|
||||
returnedBalanceErr: errors.New("something went wrong"),
|
||||
addAmounts: []abi.TokenAmount{abi.NewTokenAmount(100)},
|
||||
expectedResults: []expectedResult{
|
||||
{
|
||||
err: errors.New("something went wrong"),
|
||||
},
|
||||
},
|
||||
},
|
||||
"error on push message": {
|
||||
returnedBalance: api.MarketBalance{Escrow: abi.NewTokenAmount(0), Locked: abi.NewTokenAmount(0)},
|
||||
pushMessageErr: errors.New("something went wrong"),
|
||||
addAmounts: []abi.TokenAmount{abi.NewTokenAmount(100)},
|
||||
expectedResults: []expectedResult{
|
||||
{
|
||||
err: errors.New("something went wrong"),
|
||||
},
|
||||
},
|
||||
},
|
||||
"error looking up address": {
|
||||
lookupIDErr: errors.New("something went wrong"),
|
||||
addAmounts: []abi.TokenAmount{abi.NewTokenAmount(100)},
|
||||
expectedResults: []expectedResult{
|
||||
{
|
||||
err: errors.New("something went wrong"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for testCase, data := range testCases {
|
||||
//nolint:scopelint
|
||||
t.Run(testCase, func(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||
defer cancel()
|
||||
sig := make([]byte, 100)
|
||||
_, err := rand.Read(sig)
|
||||
require.NoError(t, err)
|
||||
fapi := &fakeAPI{
|
||||
returnedBalance: data.returnedBalance,
|
||||
returnedBalanceErr: data.returnedBalanceErr,
|
||||
signature: crypto.Signature{
|
||||
Type: crypto.SigTypeUnknown,
|
||||
Data: sig,
|
||||
},
|
||||
pushMessageErr: data.pushMessageErr,
|
||||
lookupIDErr: data.lookupIDErr,
|
||||
}
|
||||
fundMgr := newFundMgr(fapi)
|
||||
addr := tutils.NewIDAddr(t, uint64(rand.Uint32()))
|
||||
wallet := tutils.NewIDAddr(t, uint64(rand.Uint32()))
|
||||
for i, amount := range data.addAmounts {
|
||||
fapi.receivedMessage = nil
|
||||
_, err := fundMgr.EnsureAvailable(ctx, addr, wallet, amount)
|
||||
expected := data.expectedResults[i]
|
||||
if expected.err == nil {
|
||||
require.NoError(t, err)
|
||||
if expected.shouldAdd {
|
||||
expectedMessage := addFundsMsg(expected.addAmt, addr, wallet)
|
||||
require.Equal(t, expectedMessage, fapi.receivedMessage)
|
||||
} else {
|
||||
require.Nil(t, fapi.receivedMessage)
|
||||
}
|
||||
} else {
|
||||
require.EqualError(t, err, expected.err.Error())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package messagepool
|
||||
|
||||
import (
|
||||
"math"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var noWinnersProbCache []float64
|
||||
var noWinnersProbOnce sync.Once
|
||||
|
||||
func noWinnersProb() []float64 {
|
||||
noWinnersProbOnce.Do(func() {
|
||||
poissPdf := func(x float64) float64 {
|
||||
const Mu = 5
|
||||
lg, _ := math.Lgamma(x + 1)
|
||||
result := math.Exp((math.Log(Mu) * x) - lg - Mu)
|
||||
return result
|
||||
}
|
||||
|
||||
out := make([]float64, 0, MaxBlocks)
|
||||
for i := 0; i < MaxBlocks; i++ {
|
||||
out = append(out, poissPdf(float64(i)))
|
||||
}
|
||||
noWinnersProbCache = out
|
||||
})
|
||||
return noWinnersProbCache
|
||||
}
|
||||
|
||||
var noWinnersProbAssumingCache []float64
|
||||
var noWinnersProbAssumingOnce sync.Once
|
||||
|
||||
func noWinnersProbAssumingMoreThanOne() []float64 {
|
||||
noWinnersProbAssumingOnce.Do(func() {
|
||||
cond := math.Log(-1 + math.Exp(5))
|
||||
poissPdf := func(x float64) float64 {
|
||||
const Mu = 5
|
||||
lg, _ := math.Lgamma(x + 1)
|
||||
result := math.Exp((math.Log(Mu) * x) - lg - cond)
|
||||
return result
|
||||
}
|
||||
|
||||
out := make([]float64, 0, MaxBlocks)
|
||||
for i := 0; i < MaxBlocks; i++ {
|
||||
out = append(out, poissPdf(float64(i+1)))
|
||||
}
|
||||
noWinnersProbAssumingCache = out
|
||||
})
|
||||
return noWinnersProbAssumingCache
|
||||
}
|
||||
|
||||
func binomialCoefficient(n, k float64) float64 {
|
||||
if k > n {
|
||||
return math.NaN()
|
||||
}
|
||||
r := 1.0
|
||||
for d := 1.0; d <= k; d++ {
|
||||
r *= n
|
||||
r /= d
|
||||
n--
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (mp *MessagePool) blockProbabilities(tq float64) []float64 {
|
||||
noWinners := noWinnersProbAssumingMoreThanOne()
|
||||
|
||||
p := 1 - tq
|
||||
binoPdf := func(x, trials float64) float64 {
|
||||
// based on https://github.com/atgjack/prob
|
||||
if x > trials {
|
||||
return 0
|
||||
}
|
||||
if p == 0 {
|
||||
if x == 0 {
|
||||
return 1.0
|
||||
}
|
||||
return 0.0
|
||||
}
|
||||
if p == 1 {
|
||||
if x == trials {
|
||||
return 1.0
|
||||
}
|
||||
return 0.0
|
||||
}
|
||||
coef := binomialCoefficient(trials, x)
|
||||
pow := math.Pow(p, x) * math.Pow(1-p, trials-x)
|
||||
if math.IsInf(coef, 0) {
|
||||
return 0
|
||||
}
|
||||
return coef * pow
|
||||
}
|
||||
|
||||
out := make([]float64, 0, MaxBlocks)
|
||||
for place := 0; place < MaxBlocks; place++ {
|
||||
var pPlace float64
|
||||
for otherWinners, pCase := range noWinners {
|
||||
pPlace += pCase * binoPdf(float64(place), float64(otherWinners))
|
||||
}
|
||||
out = append(out, pPlace)
|
||||
}
|
||||
return out
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package messagepool
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/rand"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestBlockProbability(t *testing.T) {
|
||||
mp := &MessagePool{}
|
||||
bp := mp.blockProbabilities(1 - 0.15)
|
||||
t.Logf("%+v\n", bp)
|
||||
for i := 0; i < len(bp)-1; i++ {
|
||||
if bp[i] < bp[i+1] {
|
||||
t.Fatalf("expected decreasing block probabilities for this quality: %d %f %f",
|
||||
i, bp[i], bp[i+1])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWinnerProba(t *testing.T) {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
const N = 1000000
|
||||
winnerProba := noWinnersProb()
|
||||
sum := 0
|
||||
for i := 0; i < N; i++ {
|
||||
minersRand := rand.Float64()
|
||||
j := 0
|
||||
for ; j < MaxBlocks; j++ {
|
||||
minersRand -= winnerProba[j]
|
||||
if minersRand < 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
sum += j
|
||||
}
|
||||
|
||||
if avg := float64(sum) / N; math.Abs(avg-5) > 0.01 {
|
||||
t.Fatalf("avg too far off: %f", avg)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package messagepool
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
"github.com/ipfs/go-datastore"
|
||||
)
|
||||
|
||||
var (
|
||||
ReplaceByFeeRatioDefault = 1.25
|
||||
MemPoolSizeLimitHiDefault = 30000
|
||||
MemPoolSizeLimitLoDefault = 20000
|
||||
PruneCooldownDefault = time.Minute
|
||||
GasLimitOverestimation = 1.25
|
||||
|
||||
ConfigKey = datastore.NewKey("/mpool/config")
|
||||
)
|
||||
|
||||
func loadConfig(ds dtypes.MetadataDS) (*types.MpoolConfig, error) {
|
||||
haveCfg, err := ds.Has(ConfigKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !haveCfg {
|
||||
return DefaultConfig(), nil
|
||||
}
|
||||
|
||||
cfgBytes, err := ds.Get(ConfigKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfg := new(types.MpoolConfig)
|
||||
err = json.Unmarshal(cfgBytes, cfg)
|
||||
return cfg, err
|
||||
}
|
||||
|
||||
func saveConfig(cfg *types.MpoolConfig, ds dtypes.MetadataDS) error {
|
||||
cfgBytes, err := json.Marshal(cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ds.Put(ConfigKey, cfgBytes)
|
||||
}
|
||||
|
||||
func (mp *MessagePool) GetConfig() *types.MpoolConfig {
|
||||
mp.cfgLk.Lock()
|
||||
defer mp.cfgLk.Unlock()
|
||||
return mp.cfg.Clone()
|
||||
}
|
||||
|
||||
func validateConfg(cfg *types.MpoolConfig) error {
|
||||
if cfg.ReplaceByFeeRatio < ReplaceByFeeRatioDefault {
|
||||
return fmt.Errorf("'ReplaceByFeeRatio' is less than required %f < %f",
|
||||
cfg.ReplaceByFeeRatio, ReplaceByFeeRatioDefault)
|
||||
}
|
||||
if cfg.GasLimitOverestimation < 1 {
|
||||
return fmt.Errorf("'GasLimitOverestimation' cannot be less than 1")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mp *MessagePool) SetConfig(cfg *types.MpoolConfig) error {
|
||||
if err := validateConfg(cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
cfg = cfg.Clone()
|
||||
|
||||
mp.cfgLk.Lock()
|
||||
mp.cfg = cfg
|
||||
err := saveConfig(cfg, mp.ds)
|
||||
if err != nil {
|
||||
log.Warnf("error persisting mpool config: %s", err)
|
||||
}
|
||||
mp.cfgLk.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func DefaultConfig() *types.MpoolConfig {
|
||||
return &types.MpoolConfig{
|
||||
SizeLimitHigh: MemPoolSizeLimitHiDefault,
|
||||
SizeLimitLow: MemPoolSizeLimitLoDefault,
|
||||
ReplaceByFeeRatio: ReplaceByFeeRatioDefault,
|
||||
PruneCooldown: PruneCooldownDefault,
|
||||
GasLimitOverestimation: GasLimitOverestimation,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package gasguess
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
)
|
||||
|
||||
type ActorLookup func(context.Context, address.Address, types.TipSetKey) (*types.Actor, error)
|
||||
|
||||
const failedGasGuessRatio = 0.5
|
||||
const failedGasGuessMax = 25_000_000
|
||||
|
||||
const MinGas = 1298450
|
||||
const MaxGas = 1600271356
|
||||
|
||||
type CostKey struct {
|
||||
Code cid.Cid
|
||||
M abi.MethodNum
|
||||
}
|
||||
|
||||
var Costs = map[CostKey]int64{
|
||||
{builtin.InitActorCodeID, 2}: 8916753,
|
||||
{builtin.StorageMarketActorCodeID, 2}: 6955002,
|
||||
{builtin.StorageMarketActorCodeID, 4}: 245436108,
|
||||
{builtin.StorageMinerActorCodeID, 4}: 2315133,
|
||||
{builtin.StorageMinerActorCodeID, 5}: 1600271356,
|
||||
{builtin.StorageMinerActorCodeID, 6}: 22864493,
|
||||
{builtin.StorageMinerActorCodeID, 7}: 142002419,
|
||||
{builtin.StorageMinerActorCodeID, 10}: 23008274,
|
||||
{builtin.StorageMinerActorCodeID, 11}: 19303178,
|
||||
{builtin.StorageMinerActorCodeID, 14}: 566356835,
|
||||
{builtin.StorageMinerActorCodeID, 16}: 5325185,
|
||||
{builtin.StorageMinerActorCodeID, 18}: 2328637,
|
||||
{builtin.StoragePowerActorCodeID, 2}: 23600956,
|
||||
}
|
||||
|
||||
func failedGuess(msg *types.SignedMessage) int64 {
|
||||
guess := int64(float64(msg.Message.GasLimit) * failedGasGuessRatio)
|
||||
if guess > failedGasGuessMax {
|
||||
guess = failedGasGuessMax
|
||||
}
|
||||
return guess
|
||||
}
|
||||
|
||||
func GuessGasUsed(ctx context.Context, tsk types.TipSetKey, msg *types.SignedMessage, al ActorLookup) (int64, error) {
|
||||
if msg.Message.Method == builtin.MethodSend {
|
||||
switch msg.Message.From.Protocol() {
|
||||
case address.BLS:
|
||||
return 1298450, nil
|
||||
case address.SECP256K1:
|
||||
return 1385999, nil
|
||||
default:
|
||||
// who knows?
|
||||
return 1298450, nil
|
||||
}
|
||||
}
|
||||
|
||||
to, err := al(ctx, msg.Message.To, tsk)
|
||||
if err != nil {
|
||||
return failedGuess(msg), xerrors.Errorf("could not lookup actor: %w", err)
|
||||
}
|
||||
|
||||
guess, ok := Costs[CostKey{to.Code, msg.Message.Method}]
|
||||
if !ok {
|
||||
return failedGuess(msg), xerrors.Errorf("unknown code-method combo")
|
||||
}
|
||||
if guess > msg.Message.GasLimit {
|
||||
guess = msg.Message.GasLimit
|
||||
}
|
||||
return guess, nil
|
||||
}
|
||||
+636
-236
File diff suppressed because it is too large
Load Diff
@@ -3,33 +3,65 @@ package messagepool
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"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"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-datastore"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
)
|
||||
|
||||
func init() {
|
||||
_ = logging.SetLogLevel("*", "INFO")
|
||||
}
|
||||
|
||||
type testMpoolAPI struct {
|
||||
cb func(rev, app []*types.TipSet) error
|
||||
|
||||
bmsgs map[cid.Cid][]*types.SignedMessage
|
||||
statenonce map[address.Address]uint64
|
||||
balance map[address.Address]types.BigInt
|
||||
|
||||
tipsets []*types.TipSet
|
||||
|
||||
published int
|
||||
|
||||
baseFee types.BigInt
|
||||
}
|
||||
|
||||
func newTestMpoolAPI() *testMpoolAPI {
|
||||
return &testMpoolAPI{
|
||||
tma := &testMpoolAPI{
|
||||
bmsgs: make(map[cid.Cid][]*types.SignedMessage),
|
||||
statenonce: make(map[address.Address]uint64),
|
||||
balance: make(map[address.Address]types.BigInt),
|
||||
baseFee: types.NewInt(100),
|
||||
}
|
||||
genesis := mock.MkBlock(nil, 1, 1)
|
||||
tma.tipsets = append(tma.tipsets, mock.TipSet(genesis))
|
||||
return tma
|
||||
}
|
||||
|
||||
func (tma *testMpoolAPI) nextBlock() *types.BlockHeader {
|
||||
newBlk := mock.MkBlock(tma.tipsets[len(tma.tipsets)-1], 1, 1)
|
||||
tma.tipsets = append(tma.tipsets, mock.TipSet(newBlk))
|
||||
return newBlk
|
||||
}
|
||||
|
||||
func (tma *testMpoolAPI) nextBlockWithHeight(height uint64) *types.BlockHeader {
|
||||
newBlk := mock.MkBlock(tma.tipsets[len(tma.tipsets)-1], 1, 1)
|
||||
newBlk.Height = abi.ChainEpoch(height)
|
||||
tma.tipsets = append(tma.tipsets, mock.TipSet(newBlk))
|
||||
return newBlk
|
||||
}
|
||||
|
||||
func (tma *testMpoolAPI) applyBlock(t *testing.T, b *types.BlockHeader) {
|
||||
@@ -50,14 +82,21 @@ func (tma *testMpoolAPI) setStateNonce(addr address.Address, v uint64) {
|
||||
tma.statenonce[addr] = v
|
||||
}
|
||||
|
||||
func (tma *testMpoolAPI) setBalance(addr address.Address, v uint64) {
|
||||
tma.balance[addr] = types.FromFil(v)
|
||||
}
|
||||
|
||||
func (tma *testMpoolAPI) setBalanceRaw(addr address.Address, v types.BigInt) {
|
||||
tma.balance[addr] = v
|
||||
}
|
||||
|
||||
func (tma *testMpoolAPI) setBlockMessages(h *types.BlockHeader, msgs ...*types.SignedMessage) {
|
||||
tma.bmsgs[h.Cid()] = msgs
|
||||
tma.tipsets = append(tma.tipsets, mock.TipSet(h))
|
||||
}
|
||||
|
||||
func (tma *testMpoolAPI) SubscribeHeadChanges(cb func(rev, app []*types.TipSet) error) *types.TipSet {
|
||||
tma.cb = cb
|
||||
return nil
|
||||
return tma.tipsets[0]
|
||||
}
|
||||
|
||||
func (tma *testMpoolAPI) PutMessage(m types.ChainMsg) (cid.Cid, error) {
|
||||
@@ -65,13 +104,48 @@ func (tma *testMpoolAPI) PutMessage(m types.ChainMsg) (cid.Cid, error) {
|
||||
}
|
||||
|
||||
func (tma *testMpoolAPI) PubSubPublish(string, []byte) error {
|
||||
tma.published++
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tma *testMpoolAPI) StateGetActor(addr address.Address, ts *types.TipSet) (*types.Actor, error) {
|
||||
func (tma *testMpoolAPI) GetActorAfter(addr address.Address, ts *types.TipSet) (*types.Actor, error) {
|
||||
// regression check for load bug
|
||||
if ts == nil {
|
||||
panic("GetActorAfter called with nil tipset")
|
||||
}
|
||||
|
||||
balance, ok := tma.balance[addr]
|
||||
if !ok {
|
||||
balance = types.NewInt(1000e6)
|
||||
tma.balance[addr] = balance
|
||||
}
|
||||
|
||||
msgs := make([]*types.SignedMessage, 0)
|
||||
for _, b := range ts.Blocks() {
|
||||
for _, m := range tma.bmsgs[b.Cid()] {
|
||||
if m.Message.From == addr {
|
||||
msgs = append(msgs, m)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(msgs, func(i, j int) bool {
|
||||
return msgs[i].Message.Nonce < msgs[j].Message.Nonce
|
||||
})
|
||||
|
||||
nonce := tma.statenonce[addr]
|
||||
|
||||
for _, m := range msgs {
|
||||
if m.Message.Nonce != nonce {
|
||||
break
|
||||
}
|
||||
nonce++
|
||||
}
|
||||
|
||||
return &types.Actor{
|
||||
Nonce: tma.statenonce[addr],
|
||||
Balance: types.NewInt(90000000),
|
||||
Code: builtin.StorageMarketActorCodeID,
|
||||
Nonce: nonce,
|
||||
Balance: balance,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -118,6 +192,10 @@ func (tma *testMpoolAPI) LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error)
|
||||
return nil, fmt.Errorf("tipset not found")
|
||||
}
|
||||
|
||||
func (tma *testMpoolAPI) ChainComputeBaseFee(ctx context.Context, ts *types.TipSet) (types.BigInt, error) {
|
||||
return tma.baseFee, nil
|
||||
}
|
||||
|
||||
func assertNonce(t *testing.T, mp *MessagePool, addr address.Address, val uint64) {
|
||||
t.Helper()
|
||||
n, err := mp.GetNonce(addr)
|
||||
@@ -152,7 +230,7 @@ func TestMessagePool(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a := mock.MkBlock(nil, 1, 1)
|
||||
a := tma.nextBlock()
|
||||
|
||||
sender, err := w.GenerateKey(crypto.SigTypeBLS)
|
||||
if err != nil {
|
||||
@@ -178,7 +256,7 @@ func TestMessagePool(t *testing.T) {
|
||||
assertNonce(t, mp, sender, 2)
|
||||
}
|
||||
|
||||
func TestRevertMessages(t *testing.T) {
|
||||
func TestMessagePoolMessagesInEachBlock(t *testing.T) {
|
||||
tma := newTestMpoolAPI()
|
||||
|
||||
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
@@ -193,8 +271,57 @@ func TestRevertMessages(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a := mock.MkBlock(nil, 1, 1)
|
||||
b := mock.MkBlock(mock.TipSet(a), 1, 1)
|
||||
a := tma.nextBlock()
|
||||
|
||||
sender, err := w.GenerateKey(crypto.SigTypeBLS)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
target := mock.Address(1001)
|
||||
|
||||
var msgs []*types.SignedMessage
|
||||
for i := 0; i < 5; i++ {
|
||||
m := mock.MkMessage(sender, target, uint64(i), w)
|
||||
msgs = append(msgs, m)
|
||||
mustAdd(t, mp, m)
|
||||
}
|
||||
|
||||
tma.setStateNonce(sender, 0)
|
||||
|
||||
tma.setBlockMessages(a, msgs[0], msgs[1])
|
||||
tma.applyBlock(t, a)
|
||||
tsa := mock.TipSet(a)
|
||||
|
||||
_, _ = mp.Pending()
|
||||
|
||||
selm, _ := mp.SelectMessages(tsa, 1)
|
||||
if len(selm) == 0 {
|
||||
t.Fatal("should have returned the rest of the messages")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRevertMessages(t *testing.T) {
|
||||
futureDebug = true
|
||||
defer func() {
|
||||
futureDebug = false
|
||||
}()
|
||||
|
||||
tma := newTestMpoolAPI()
|
||||
|
||||
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ds := datastore.NewMapDatastore()
|
||||
|
||||
mp, err := New(tma, ds, "mptest")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a := tma.nextBlock()
|
||||
b := tma.nextBlock()
|
||||
|
||||
sender, err := w.GenerateKey(crypto.SigTypeBLS)
|
||||
if err != nil {
|
||||
@@ -228,8 +355,319 @@ func TestRevertMessages(t *testing.T) {
|
||||
assertNonce(t, mp, sender, 4)
|
||||
|
||||
p, _ := mp.Pending()
|
||||
fmt.Printf("%+v\n", p)
|
||||
if len(p) != 3 {
|
||||
t.Fatal("expected three messages in mempool")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestPruningSimple(t *testing.T) {
|
||||
oldMaxNonceGap := MaxNonceGap
|
||||
MaxNonceGap = 1000
|
||||
defer func() {
|
||||
MaxNonceGap = oldMaxNonceGap
|
||||
}()
|
||||
|
||||
tma := newTestMpoolAPI()
|
||||
|
||||
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ds := datastore.NewMapDatastore()
|
||||
|
||||
mp, err := New(tma, ds, "mptest")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a := tma.nextBlock()
|
||||
tma.applyBlock(t, a)
|
||||
|
||||
sender, err := w.GenerateKey(crypto.SigTypeBLS)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tma.setBalance(sender, 1) // in FIL
|
||||
target := mock.Address(1001)
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
smsg := mock.MkMessage(sender, target, uint64(i), w)
|
||||
if err := mp.Add(smsg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
for i := 10; i < 50; i++ {
|
||||
smsg := mock.MkMessage(sender, target, uint64(i), w)
|
||||
if err := mp.Add(smsg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
mp.cfg.SizeLimitHigh = 40
|
||||
mp.cfg.SizeLimitLow = 10
|
||||
|
||||
mp.Prune()
|
||||
|
||||
msgs, _ := mp.Pending()
|
||||
if len(msgs) != 5 {
|
||||
t.Fatal("expected only 5 messages in pool, got: ", len(msgs))
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadLocal(t *testing.T) {
|
||||
tma := newTestMpoolAPI()
|
||||
ds := datastore.NewMapDatastore()
|
||||
|
||||
mp, err := New(tma, ds, "mptest")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// the actors
|
||||
w1, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
w2, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tma.setBalance(a1, 1) // in FIL
|
||||
tma.setBalance(a2, 1) // in FIL
|
||||
gasLimit := gasguess.Costs[gasguess.CostKey{Code: builtin.StorageMarketActorCodeID, M: 2}]
|
||||
msgs := make(map[cid.Cid]struct{})
|
||||
for i := 0; i < 10; i++ {
|
||||
m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(i+1))
|
||||
cid, err := mp.Push(m)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
msgs[cid] = struct{}{}
|
||||
}
|
||||
err = mp.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
mp, err = New(tma, ds, "mptest")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
pmsgs, _ := mp.Pending()
|
||||
if len(msgs) != len(pmsgs) {
|
||||
t.Fatalf("expected %d messages, but got %d", len(msgs), len(pmsgs))
|
||||
}
|
||||
|
||||
for _, m := range pmsgs {
|
||||
cid := m.Cid()
|
||||
_, ok := msgs[cid]
|
||||
if !ok {
|
||||
t.Fatal("unknown message")
|
||||
}
|
||||
|
||||
delete(msgs, cid)
|
||||
}
|
||||
|
||||
if len(msgs) > 0 {
|
||||
t.Fatalf("not all messages were laoded; missing %d messages", len(msgs))
|
||||
}
|
||||
}
|
||||
|
||||
func TestClearAll(t *testing.T) {
|
||||
tma := newTestMpoolAPI()
|
||||
ds := datastore.NewMapDatastore()
|
||||
|
||||
mp, err := New(tma, ds, "mptest")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// the actors
|
||||
w1, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
w2, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tma.setBalance(a1, 1) // in FIL
|
||||
tma.setBalance(a2, 1) // in FIL
|
||||
gasLimit := gasguess.Costs[gasguess.CostKey{Code: builtin.StorageMarketActorCodeID, M: 2}]
|
||||
for i := 0; i < 10; i++ {
|
||||
m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(i+1))
|
||||
_, err := mp.Push(m)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
m := makeTestMessage(w2, a2, a1, uint64(i), gasLimit, uint64(i+1))
|
||||
mustAdd(t, mp, m)
|
||||
}
|
||||
|
||||
mp.Clear(true)
|
||||
|
||||
pending, _ := mp.Pending()
|
||||
if len(pending) > 0 {
|
||||
t.Fatalf("cleared the mpool, but got %d pending messages", len(pending))
|
||||
}
|
||||
}
|
||||
|
||||
func TestClearNonLocal(t *testing.T) {
|
||||
tma := newTestMpoolAPI()
|
||||
ds := datastore.NewMapDatastore()
|
||||
|
||||
mp, err := New(tma, ds, "mptest")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// the actors
|
||||
w1, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
w2, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tma.setBalance(a1, 1) // in FIL
|
||||
tma.setBalance(a2, 1) // in FIL
|
||||
|
||||
gasLimit := gasguess.Costs[gasguess.CostKey{Code: builtin.StorageMarketActorCodeID, M: 2}]
|
||||
for i := 0; i < 10; i++ {
|
||||
m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(i+1))
|
||||
_, err := mp.Push(m)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
m := makeTestMessage(w2, a2, a1, uint64(i), gasLimit, uint64(i+1))
|
||||
mustAdd(t, mp, m)
|
||||
}
|
||||
|
||||
mp.Clear(false)
|
||||
|
||||
pending, _ := mp.Pending()
|
||||
if len(pending) != 10 {
|
||||
t.Fatalf("expected 10 pending messages, but got %d instead", len(pending))
|
||||
}
|
||||
|
||||
for _, m := range pending {
|
||||
if m.Message.From != a1 {
|
||||
t.Fatalf("expected message from %s but got one from %s instead", a1, m.Message.From)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdates(t *testing.T) {
|
||||
tma := newTestMpoolAPI()
|
||||
ds := datastore.NewMapDatastore()
|
||||
|
||||
mp, err := New(tma, ds, "mptest")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// the actors
|
||||
w1, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
w2, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.TODO())
|
||||
defer cancel()
|
||||
|
||||
ch, err := mp.Updates(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
gasLimit := gasguess.Costs[gasguess.CostKey{Code: builtin.StorageMarketActorCodeID, M: 2}]
|
||||
|
||||
tma.setBalance(a1, 1) // in FIL
|
||||
tma.setBalance(a2, 1) // in FIL
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(i+1))
|
||||
_, err := mp.Push(m)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, ok := <-ch
|
||||
if !ok {
|
||||
t.Fatal("expected update, but got a closed channel instead")
|
||||
}
|
||||
}
|
||||
|
||||
err = mp.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, ok := <-ch
|
||||
if ok {
|
||||
t.Fatal("expected closed channel, but got an update instead")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
package messagepool
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
type Provider interface {
|
||||
SubscribeHeadChanges(func(rev, app []*types.TipSet) error) *types.TipSet
|
||||
PutMessage(m types.ChainMsg) (cid.Cid, error)
|
||||
PubSubPublish(string, []byte) error
|
||||
GetActorAfter(address.Address, *types.TipSet) (*types.Actor, error)
|
||||
StateAccountKey(context.Context, address.Address, *types.TipSet) (address.Address, error)
|
||||
MessagesForBlock(*types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error)
|
||||
MessagesForTipset(*types.TipSet) ([]types.ChainMsg, error)
|
||||
LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error)
|
||||
ChainComputeBaseFee(ctx context.Context, ts *types.TipSet) (types.BigInt, error)
|
||||
}
|
||||
|
||||
type mpoolProvider struct {
|
||||
sm *stmgr.StateManager
|
||||
ps *pubsub.PubSub
|
||||
}
|
||||
|
||||
func NewProvider(sm *stmgr.StateManager, ps *pubsub.PubSub) Provider {
|
||||
return &mpoolProvider{sm: sm, ps: ps}
|
||||
}
|
||||
|
||||
func (mpp *mpoolProvider) SubscribeHeadChanges(cb func(rev, app []*types.TipSet) error) *types.TipSet {
|
||||
mpp.sm.ChainStore().SubscribeHeadChanges(cb)
|
||||
return mpp.sm.ChainStore().GetHeaviestTipSet()
|
||||
}
|
||||
|
||||
func (mpp *mpoolProvider) PutMessage(m types.ChainMsg) (cid.Cid, error) {
|
||||
return mpp.sm.ChainStore().PutMessage(m)
|
||||
}
|
||||
|
||||
func (mpp *mpoolProvider) PubSubPublish(k string, v []byte) error {
|
||||
return mpp.ps.Publish(k, v) //nolint
|
||||
}
|
||||
|
||||
func (mpp *mpoolProvider) GetActorAfter(addr address.Address, ts *types.TipSet) (*types.Actor, error) {
|
||||
var act types.Actor
|
||||
stcid, _, err := mpp.sm.TipSetState(context.TODO(), ts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("computing tipset state for GetActor: %w", err)
|
||||
}
|
||||
|
||||
return &act, mpp.sm.WithStateTree(stcid, mpp.sm.WithActor(addr, stmgr.GetActor(&act)))
|
||||
}
|
||||
|
||||
func (mpp *mpoolProvider) StateAccountKey(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
|
||||
return mpp.sm.ResolveToKeyAddress(ctx, addr, ts)
|
||||
}
|
||||
|
||||
func (mpp *mpoolProvider) MessagesForBlock(h *types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error) {
|
||||
return mpp.sm.ChainStore().MessagesForBlock(h)
|
||||
}
|
||||
|
||||
func (mpp *mpoolProvider) MessagesForTipset(ts *types.TipSet) ([]types.ChainMsg, error) {
|
||||
return mpp.sm.ChainStore().MessagesForTipset(ts)
|
||||
}
|
||||
|
||||
func (mpp *mpoolProvider) LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error) {
|
||||
return mpp.sm.ChainStore().LoadTipSet(tsk)
|
||||
}
|
||||
|
||||
func (mpp *mpoolProvider) ChainComputeBaseFee(ctx context.Context, ts *types.TipSet) (types.BigInt, error) {
|
||||
baseFee, err := mpp.sm.ChainStore().ComputeBaseFee(ctx, ts)
|
||||
if err != nil {
|
||||
return types.NewInt(0), xerrors.Errorf("computing base fee at %s: %w", ts, err)
|
||||
}
|
||||
return baseFee, nil
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package messagepool
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/ipfs/go-cid"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
func (mp *MessagePool) pruneExcessMessages() error {
|
||||
mp.curTsLk.Lock()
|
||||
ts := mp.curTs
|
||||
mp.curTsLk.Unlock()
|
||||
|
||||
mp.lk.Lock()
|
||||
defer mp.lk.Unlock()
|
||||
|
||||
if mp.currentSize < mp.cfg.SizeLimitHigh {
|
||||
return nil
|
||||
}
|
||||
|
||||
select {
|
||||
case <-mp.pruneCooldown:
|
||||
err := mp.pruneMessages(context.TODO(), ts)
|
||||
go func() {
|
||||
time.Sleep(mp.cfg.PruneCooldown)
|
||||
mp.pruneCooldown <- struct{}{}
|
||||
}()
|
||||
return err
|
||||
default:
|
||||
return xerrors.New("cannot prune before cooldown")
|
||||
}
|
||||
}
|
||||
|
||||
func (mp *MessagePool) pruneMessages(ctx context.Context, ts *types.TipSet) error {
|
||||
start := time.Now()
|
||||
defer func() {
|
||||
log.Infof("message pruning took %s", time.Since(start))
|
||||
}()
|
||||
|
||||
baseFee, err := mp.api.ChainComputeBaseFee(ctx, ts)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("computing basefee: %w", err)
|
||||
}
|
||||
|
||||
pending, _ := mp.getPendingMessages(ts, ts)
|
||||
|
||||
// priority actors -- not pruned
|
||||
priority := make(map[address.Address]struct{})
|
||||
for _, actor := range mp.cfg.PriorityAddrs {
|
||||
priority[actor] = struct{}{}
|
||||
}
|
||||
|
||||
// Collect all messages to track which ones to remove and create chains for block inclusion
|
||||
pruneMsgs := make(map[cid.Cid]*types.SignedMessage, mp.currentSize)
|
||||
keepCount := 0
|
||||
|
||||
var chains []*msgChain
|
||||
for actor, mset := range pending {
|
||||
// we never prune priority actors
|
||||
_, keep := priority[actor]
|
||||
if keep {
|
||||
keepCount += len(mset)
|
||||
continue
|
||||
}
|
||||
|
||||
// not a priority actor, track the messages and create chains
|
||||
for _, m := range mset {
|
||||
pruneMsgs[m.Message.Cid()] = m
|
||||
}
|
||||
actorChains := mp.createMessageChains(actor, mset, baseFee, ts)
|
||||
chains = append(chains, actorChains...)
|
||||
}
|
||||
|
||||
// Sort the chains
|
||||
sort.Slice(chains, func(i, j int) bool {
|
||||
return chains[i].Before(chains[j])
|
||||
})
|
||||
|
||||
// Keep messages (remove them from pruneMsgs) from chains while we are under the low water mark
|
||||
loWaterMark := mp.cfg.SizeLimitLow
|
||||
keepLoop:
|
||||
for _, chain := range chains {
|
||||
for _, m := range chain.msgs {
|
||||
if keepCount < loWaterMark {
|
||||
delete(pruneMsgs, m.Message.Cid())
|
||||
keepCount++
|
||||
} else {
|
||||
break keepLoop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// and remove all messages that are still in pruneMsgs after processing the chains
|
||||
log.Infof("Pruning %d messages", len(pruneMsgs))
|
||||
for _, m := range pruneMsgs {
|
||||
mp.remove(m.Message.From, m.Message.Nonce, false)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
package messagepool
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/messagepool/gasguess"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/ipfs/go-cid"
|
||||
)
|
||||
|
||||
const repubMsgLimit = 30
|
||||
|
||||
var RepublishBatchDelay = 100 * time.Millisecond
|
||||
|
||||
func (mp *MessagePool) republishPendingMessages() error {
|
||||
mp.curTsLk.Lock()
|
||||
ts := mp.curTs
|
||||
|
||||
baseFee, err := mp.api.ChainComputeBaseFee(context.TODO(), ts)
|
||||
if err != nil {
|
||||
mp.curTsLk.Unlock()
|
||||
return xerrors.Errorf("computing basefee: %w", err)
|
||||
}
|
||||
|
||||
baseFeeLowerBound := types.BigDiv(baseFee, baseFeeLowerBoundFactor)
|
||||
if baseFeeLowerBoundFactor.LessThan(minimumBaseFee) {
|
||||
baseFeeLowerBound = minimumBaseFee
|
||||
}
|
||||
|
||||
pending := make(map[address.Address]map[uint64]*types.SignedMessage)
|
||||
mp.lk.Lock()
|
||||
mp.republished = nil // clear this to avoid races triggering an early republish
|
||||
for actor := range mp.localAddrs {
|
||||
mset, ok := mp.pending[actor]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if len(mset.msgs) == 0 {
|
||||
continue
|
||||
}
|
||||
// we need to copy this while holding the lock to avoid races with concurrent modification
|
||||
pend := make(map[uint64]*types.SignedMessage, len(mset.msgs))
|
||||
for nonce, m := range mset.msgs {
|
||||
pend[nonce] = m
|
||||
}
|
||||
pending[actor] = pend
|
||||
}
|
||||
mp.lk.Unlock()
|
||||
mp.curTsLk.Unlock()
|
||||
|
||||
if len(pending) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var chains []*msgChain
|
||||
for actor, mset := range pending {
|
||||
// We use the baseFee lower bound for createChange so that we optimistically include
|
||||
// chains that might become profitable in the next 20 blocks.
|
||||
// We still check the lowerBound condition for individual messages so that we don't send
|
||||
// messages that will be rejected by the mpool spam protector, so this is safe to do.
|
||||
next := mp.createMessageChains(actor, mset, baseFeeLowerBound, ts)
|
||||
chains = append(chains, next...)
|
||||
}
|
||||
|
||||
if len(chains) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
sort.Slice(chains, func(i, j int) bool {
|
||||
return chains[i].Before(chains[j])
|
||||
})
|
||||
|
||||
gasLimit := int64(build.BlockGasLimit)
|
||||
minGas := int64(gasguess.MinGas)
|
||||
var msgs []*types.SignedMessage
|
||||
loop:
|
||||
for i := 0; i < len(chains); {
|
||||
chain := chains[i]
|
||||
|
||||
// we can exceed this if we have picked (some) longer chain already
|
||||
if len(msgs) > repubMsgLimit {
|
||||
break
|
||||
}
|
||||
|
||||
// there is not enough gas for any message
|
||||
if gasLimit <= minGas {
|
||||
break
|
||||
}
|
||||
|
||||
// has the chain been invalidated?
|
||||
if !chain.valid {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
||||
// does it fit in a block?
|
||||
if chain.gasLimit <= gasLimit {
|
||||
// check the baseFee lower bound -- only republish messages that can be included in the chain
|
||||
// within the next 20 blocks.
|
||||
for _, m := range chain.msgs {
|
||||
if !allowNegativeChains(ts.Height()) && m.Message.GasFeeCap.LessThan(baseFeeLowerBound) {
|
||||
chain.Invalidate()
|
||||
continue loop
|
||||
}
|
||||
gasLimit -= m.Message.GasLimit
|
||||
msgs = append(msgs, m)
|
||||
}
|
||||
|
||||
// we processed the whole chain, advance
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
||||
// we can't fit the current chain but there is gas to spare
|
||||
// trim it and push it down
|
||||
chain.Trim(gasLimit, mp, baseFee, true)
|
||||
for j := i; j < len(chains)-1; j++ {
|
||||
if chains[j].Before(chains[j+1]) {
|
||||
break
|
||||
}
|
||||
chains[j], chains[j+1] = chains[j+1], chains[j]
|
||||
}
|
||||
}
|
||||
|
||||
count := 0
|
||||
log.Infof("republishing %d messages", len(msgs))
|
||||
for _, m := range msgs {
|
||||
mb, err := m.Serialize()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("cannot serialize message: %w", err)
|
||||
}
|
||||
|
||||
err = mp.api.PubSubPublish(build.MessagesTopic(mp.netName), mb)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("cannot publish: %w", err)
|
||||
}
|
||||
|
||||
count++
|
||||
|
||||
if count < len(msgs) {
|
||||
// this delay is here to encourage the pubsub subsystem to process the messages serially
|
||||
// and avoid creating nonce gaps because of concurrent validation.
|
||||
time.Sleep(RepublishBatchDelay)
|
||||
}
|
||||
}
|
||||
|
||||
// track most recently republished messages
|
||||
republished := make(map[cid.Cid]struct{})
|
||||
for _, m := range msgs[:count] {
|
||||
republished[m.Cid()] = struct{}{}
|
||||
}
|
||||
|
||||
mp.lk.Lock()
|
||||
// update the republished set so that we can trigger early republish from head changes
|
||||
mp.republished = republished
|
||||
mp.lk.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user