Compare commits
810
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de654de911 | ||
|
|
37c0f75499 | ||
|
|
5c5c1c80cf | ||
|
|
e91ee9f62a | ||
|
|
213b4eace8 | ||
|
|
f695c0c164 | ||
|
|
194b6eb9d8 | ||
|
|
2aba16e2c9 | ||
|
|
0b09082450 | ||
|
|
29aa972f18 | ||
|
|
06b814b627 | ||
|
|
b1d251e950 | ||
|
|
8a8f0ab3ec | ||
|
|
1ef0359731 | ||
|
|
44f4372ca3 | ||
|
|
46d3769a44 | ||
|
|
65b7d71bdf | ||
|
|
3697a1af4d | ||
|
|
26ff596983 | ||
|
|
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 | ||
|
|
2233751668 | ||
|
|
b86831356b | ||
|
|
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 | ||
|
|
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 | ||
|
|
02650c7f25 | ||
|
|
936d861df5 | ||
|
|
f0d32f2c01 | ||
|
|
97489f8bf9 |
+91
-6
@@ -113,7 +113,7 @@ jobs:
|
||||
test: &test
|
||||
description: |
|
||||
Run tests with gotestsum.
|
||||
parameters:
|
||||
parameters: &test-params
|
||||
executor:
|
||||
type: executor
|
||||
default: golang
|
||||
@@ -161,6 +161,7 @@ jobs:
|
||||
name: go test
|
||||
environment:
|
||||
LOTUS_TEST_WINDOW_POST: << parameters.winpost-test >>
|
||||
SKIP_CONFORMANCE: "1"
|
||||
command: |
|
||||
mkdir -p /tmp/test-reports/<< parameters.test-suite-name >>
|
||||
mkdir -p /tmp/test-artifacts
|
||||
@@ -191,6 +192,63 @@ 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 >>
|
||||
- run:
|
||||
name: go get vectors branch
|
||||
command: go get github.com/filecoin-project/test-vectors@<< parameters.vectors-branch >>
|
||||
- go/install-gotestsum:
|
||||
gobin: $HOME/.local/bin
|
||||
version: 0.5.2
|
||||
- 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
|
||||
@@ -252,6 +310,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.
|
||||
@@ -288,9 +367,6 @@ jobs:
|
||||
command: |
|
||||
$HOME/.local/bin/golangci-lint run -v --timeout 2m \
|
||||
--concurrency << parameters.concurrency >> << parameters.args >>
|
||||
lint-changes:
|
||||
<<: *lint
|
||||
|
||||
lint-all:
|
||||
<<: *lint
|
||||
|
||||
@@ -319,10 +395,11 @@ workflows:
|
||||
version: 2.1
|
||||
ci:
|
||||
jobs:
|
||||
- lint-changes:
|
||||
args: "--new-from-rev origin/next"
|
||||
- lint-all
|
||||
- mod-tidy-check
|
||||
- gofmt
|
||||
- cbor-gen-check
|
||||
- docs-check
|
||||
- test:
|
||||
codecov-upload: true
|
||||
test-suite-name: full
|
||||
@@ -337,6 +414,14 @@ workflows:
|
||||
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
|
||||
|
||||
@@ -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-miner sectors list`.
|
||||
|
||||
**Sectors status**
|
||||
|
||||
The output of `./lotus-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 miner logs**
|
||||
|
||||
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`.
|
||||
|
||||
+8
-2
@@ -26,11 +26,14 @@
|
||||
color: 00A4E2
|
||||
description: "Area: Chain/VM"
|
||||
- name: area/chain/sync
|
||||
color: 00A4E2
|
||||
color: 00A4E4
|
||||
description: "Area: Chain/Sync"
|
||||
- name: area/chain/misc
|
||||
color: 00A4E2
|
||||
color: 00A4E6
|
||||
description: "Area: Chain/Misc"
|
||||
- name: area/markets
|
||||
color: 00A4E8
|
||||
description: "Area: Markets"
|
||||
- name: area/sealing/fsm
|
||||
color: 0bb1ed
|
||||
description: "Area: Sealing/FSM"
|
||||
@@ -149,6 +152,9 @@
|
||||
- name: impact/test-flakiness
|
||||
color: DDE1E4
|
||||
description: "Impact: Test Flakiness"
|
||||
- name: impact/consensus
|
||||
color: b20014
|
||||
description: "Impact: Consensus"
|
||||
|
||||
###
|
||||
### Topics
|
||||
|
||||
@@ -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
|
||||
|
||||
+357
-4
@@ -1,7 +1,360 @@
|
||||
# lotus changelog
|
||||
# Lotus changelog
|
||||
|
||||
## 0.1.0 / 2019-12-11
|
||||
# 0.6.1 / 2020-09-08
|
||||
|
||||
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 optional release introduces a minor improvement to the sync process, ensuring nodes don't fall behind and then resync.
|
||||
|
||||
A huge thank you to all contributors for this testnet release!
|
||||
## 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!
|
||||
|
||||
@@ -148,7 +148,7 @@ BINS+=lotus-fountain
|
||||
|
||||
lotus-chainwatch:
|
||||
rm -f lotus-chainwatch
|
||||
go build -o lotus-chainwatch ./cmd/lotus-chainwatch
|
||||
go build $(GOFLAGS) -o lotus-chainwatch ./cmd/lotus-chainwatch
|
||||
.PHONY: lotus-chainwatch
|
||||
BINS+=lotus-chainwatch
|
||||
|
||||
@@ -272,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,16 +1,24 @@
|
||||
<p align="center">
|
||||
<a href="https://docs.lotu.sh/" title="Lotus Docs">
|
||||
<a href="https://lotu.sh/" title="Lotus Docs">
|
||||
<img src="documentation/images/lotus_logo_h.png" alt="Project Lotus Logo" width="244" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<h1 align="center">Project Lotus - 莲</h1>
|
||||
|
||||
<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
|
||||
|
||||
@@ -32,9 +40,6 @@ All work is tracked via issues. An attempt at keeping an up-to-date view on rema
|
||||
The lotus Filecoin implementation unfolds into the following packages:
|
||||
|
||||
- [This repo](https://github.com/filecoin-project/lotus)
|
||||
- [storage-fsm](https://github.com/filecoin-project/storage-fsm)
|
||||
- [sector-storage](https://github.com/filecoin-project/sector-storage)
|
||||
- [specs-storage](https://github.com/filecoin-project/specs-storage)
|
||||
- [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)
|
||||
|
||||
|
||||
+17
-4
@@ -4,11 +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"
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
|
||||
"github.com/filecoin-project/go-jsonrpc/auth"
|
||||
protocol "github.com/libp2p/go-libp2p-core/protocol"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
)
|
||||
@@ -30,6 +30,19 @@ type Common interface {
|
||||
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
|
||||
|
||||
@@ -70,5 +83,5 @@ func (v Version) String() string {
|
||||
|
||||
type NatInfo struct {
|
||||
Reachability network.Reachability
|
||||
PublicAddr ma.Multiaddr
|
||||
PublicAddr string
|
||||
}
|
||||
|
||||
+111
-22
@@ -2,23 +2,27 @@ package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime/proof"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"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/go-multistore"
|
||||
"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/builtin/paych"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
marketevents "github.com/filecoin-project/lotus/markets/loggers"
|
||||
@@ -109,7 +113,10 @@ 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)
|
||||
@@ -132,6 +139,9 @@ type FullNode interface {
|
||||
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
|
||||
// observing the lotus sync service.
|
||||
@@ -181,6 +191,9 @@ type FullNode interface {
|
||||
MpoolGetNonce(context.Context, address.Address) (uint64, error)
|
||||
MpoolSub(context.Context) (<-chan MpoolUpdate, 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
|
||||
@@ -237,6 +250,8 @@ type FullNode interface {
|
||||
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).
|
||||
@@ -244,7 +259,10 @@ type FullNode interface {
|
||||
// ClientMinerQueryOffer returns a QueryOffer for the specific miner and file.
|
||||
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) (<-chan marketevents.RetrievalEvent, error)
|
||||
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
|
||||
@@ -253,6 +271,12 @@ type FullNode interface {
|
||||
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)
|
||||
@@ -283,7 +307,7 @@ 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)
|
||||
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
|
||||
@@ -298,11 +322,11 @@ type FullNode interface {
|
||||
// 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
|
||||
@@ -311,7 +335,7 @@ type FullNode interface {
|
||||
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)
|
||||
@@ -359,7 +383,7 @@ type FullNode interface {
|
||||
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) (abi.TokenAmount, error)
|
||||
StateCirculatingSupply(context.Context, types.TipSetKey) (CirculatingSupply, error)
|
||||
|
||||
// MethodGroup: Msig
|
||||
// The Msig methods are used to interact with multisig wallets on the
|
||||
@@ -404,6 +428,8 @@ type FullNode interface {
|
||||
|
||||
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)
|
||||
PaychSettle(context.Context, address.Address) (cid.Cid, error)
|
||||
@@ -412,10 +438,10 @@ type FullNode interface {
|
||||
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 {
|
||||
@@ -469,6 +495,8 @@ type DealInfo struct {
|
||||
Duration uint64
|
||||
|
||||
DealID abi.DealID
|
||||
|
||||
CreationTime time.Time
|
||||
}
|
||||
|
||||
type MsgLookup struct {
|
||||
@@ -519,6 +547,28 @@ type ChannelInfo struct {
|
||||
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
|
||||
WaitSentinel cid.Cid
|
||||
@@ -534,6 +584,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
|
||||
@@ -609,14 +669,15 @@ type MethodCall struct {
|
||||
}
|
||||
|
||||
type StartDealParams struct {
|
||||
Data *storagemarket.DataRef
|
||||
Wallet address.Address
|
||||
Miner address.Address
|
||||
EpochPrice types.BigInt
|
||||
MinBlocksDuration uint64
|
||||
DealStartEpoch abi.ChainEpoch
|
||||
FastRetrieval bool
|
||||
VerifiedDeal bool
|
||||
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 {
|
||||
@@ -649,8 +710,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 (
|
||||
@@ -673,10 +754,18 @@ type DealCollateralBounds struct {
|
||||
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
|
||||
@@ -693,7 +782,7 @@ type BlockTemplate struct {
|
||||
Messages []*types.SignedMessage
|
||||
Epoch abi.ChainEpoch
|
||||
Timestamp uint64
|
||||
WinningPoStProof []abi.PoStProof
|
||||
WinningPoStProof []proof.PoStProof
|
||||
}
|
||||
|
||||
type DataSize struct {
|
||||
|
||||
+19
-14
@@ -11,11 +11,11 @@ import (
|
||||
"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/fsutil"
|
||||
"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
|
||||
@@ -73,12 +73,14 @@ type StorageMiner interface {
|
||||
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, d cid.Cid) (<-chan storagemarket.MinerDeal, error)
|
||||
MarketGetDealUpdates(ctx context.Context) (<-chan storagemarket.MinerDeal, error)
|
||||
MarketListIncompleteDeals(ctx context.Context) ([]storagemarket.MinerDeal, 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)
|
||||
@@ -118,15 +120,18 @@ 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
|
||||
|
||||
|
||||
+9
-5
@@ -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,13 +23,17 @@ 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) (bool, error)
|
||||
|
||||
StorageAddLocal(ctx context.Context, path string) error
|
||||
|
||||
Fetch(context.Context, abi.SectorID, stores.SectorFileType, stores.PathType, stores.AcquireMode) error
|
||||
|
||||
Closing(context.Context) (<-chan struct{}, error)
|
||||
|
||||
+162
-75
@@ -6,26 +6,29 @@ import (
|
||||
"time"
|
||||
|
||||
"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/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/sector-storage/fsutil"
|
||||
"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/specs-actors/actors/builtin/miner"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/filecoin-project/specs-storage/storage"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
@@ -42,14 +45,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"`
|
||||
NetAutoNatStatus func(context.Context) (api.NatInfo, 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"`
|
||||
@@ -86,13 +93,14 @@ type FullNodeStruct struct {
|
||||
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"`
|
||||
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"`
|
||||
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"`
|
||||
@@ -105,7 +113,9 @@ type FullNodeStruct struct {
|
||||
|
||||
MpoolSelect func(context.Context, types.TipSetKey, float64) ([]*types.SignedMessage, error) `perm:"read"`
|
||||
|
||||
MpoolPending func(context.Context, types.TipSetKey) ([]*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"`
|
||||
@@ -127,32 +137,37 @@ 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) (*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"`
|
||||
ClientRetrieve 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"`
|
||||
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"`
|
||||
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) (*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.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) (abi.BitField, 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) (abi.BitField, 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"`
|
||||
@@ -181,7 +196,7 @@ type FullNodeStruct struct {
|
||||
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) (abi.TokenAmount, 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, uint64, []address.Address, abi.ChainEpoch, types.BigInt, address.Address, types.BigInt) (cid.Cid, error) `perm:"sign"`
|
||||
@@ -194,21 +209,23 @@ type FullNodeStruct struct {
|
||||
|
||||
MarketEnsureAvailable func(context.Context, address.Address, address.Address, types.BigInt) (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"`
|
||||
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) (*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"`
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,12 +245,14 @@ type StorageMinerStruct struct {
|
||||
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, d cid.Cid) (<-chan storagemarket.MinerDeal, 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"`
|
||||
|
||||
@@ -300,6 +319,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"`
|
||||
@@ -307,7 +327,8 @@ 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) (bool, error) `perm:"admin"`
|
||||
@@ -360,6 +381,22 @@ 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)
|
||||
@@ -424,10 +461,18 @@ func (c *FullNodeStruct) ClientListDeals(ctx context.Context) ([]api.DealInfo, e
|
||||
return c.Internal.ClientListDeals(ctx)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ClientRetrieve(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) (<-chan marketevents.RetrievalEvent, error) {
|
||||
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)
|
||||
}
|
||||
@@ -443,17 +488,31 @@ func (c *FullNodeStruct) ClientDealSize(ctx context.Context, root cid.Cid) (api.
|
||||
return c.Internal.ClientDealSize(ctx, root)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) GasEstimateGasPremium(ctx context.Context, nblocksincl uint64,
|
||||
sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error) {
|
||||
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) {
|
||||
|
||||
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) GasEstimateGasLimit(ctx context.Context, msg *types.Message,
|
||||
tsk types.TipSetKey) (int64, error) {
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -473,6 +532,10 @@ func (c *FullNodeStruct) MpoolPending(ctx context.Context, tsk types.TipSetKey)
|
||||
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)
|
||||
}
|
||||
@@ -621,8 +684,8 @@ 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) {
|
||||
@@ -653,7 +716,7 @@ 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)
|
||||
}
|
||||
|
||||
@@ -681,7 +744,7 @@ func (c *FullNodeStruct) StateMinerPartitions(ctx context.Context, m address.Add
|
||||
return c.Internal.StateMinerPartitions(ctx, m, dlIdx, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerFaults(ctx context.Context, actor address.Address, tsk types.TipSetKey) (abi.BitField, error) {
|
||||
func (c *FullNodeStruct) StateMinerFaults(ctx context.Context, actor address.Address, tsk types.TipSetKey) (bitfield.BitField, error) {
|
||||
return c.Internal.StateMinerFaults(ctx, actor, tsk)
|
||||
}
|
||||
|
||||
@@ -689,7 +752,7 @@ 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)
|
||||
}
|
||||
|
||||
@@ -801,7 +864,7 @@ func (c *FullNodeStruct) StateDealProviderCollateralBounds(ctx context.Context,
|
||||
return c.Internal.StateDealProviderCollateralBounds(ctx, size, verified, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateCirculatingSupply(ctx context.Context, tsk types.TipSetKey) (abi.TokenAmount, error) {
|
||||
func (c *FullNodeStruct) StateCirculatingSupply(ctx context.Context, tsk types.TipSetKey) (api.CirculatingSupply, error) {
|
||||
return c.Internal.StateCirculatingSupply(ctx, tsk)
|
||||
}
|
||||
|
||||
@@ -849,6 +912,14 @@ func (c *FullNodeStruct) PaychGetWaitReady(ctx context.Context, sentinel cid.Cid
|
||||
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) {
|
||||
return c.Internal.PaychList(ctx)
|
||||
}
|
||||
@@ -869,7 +940,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)
|
||||
}
|
||||
|
||||
@@ -893,8 +964,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
|
||||
@@ -1037,8 +1108,8 @@ func (c *StorageMinerStruct) MarketListRetrievalDeals(ctx context.Context) ([]re
|
||||
return c.Internal.MarketListRetrievalDeals(ctx)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) MarketGetDealUpdates(ctx context.Context, d cid.Cid) (<-chan storagemarket.MinerDeal, error) {
|
||||
return c.Internal.MarketGetDealUpdates(ctx, d)
|
||||
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) {
|
||||
@@ -1061,6 +1132,14 @@ func (c *StorageMinerStruct) MarketGetRetrievalAsk(ctx context.Context) (*retrie
|
||||
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)
|
||||
}
|
||||
@@ -1147,6 +1226,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)
|
||||
}
|
||||
@@ -1175,8 +1258,12 @@ 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 {
|
||||
|
||||
+2
-2
@@ -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"
|
||||
)
|
||||
|
||||
+31
-8
@@ -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,
|
||||
@@ -35,26 +40,44 @@ func NewFullNodeRPC(addr string, requestHeader http.Header) (api.FullNode, jsonr
|
||||
}
|
||||
|
||||
// NewStorageMinerRPC creates a new http jsonrpc client for miner
|
||||
func NewStorageMinerRPC(addr string, requestHeader http.Header) (api.StorageMiner, jsonrpc.ClientCloser, error) {
|
||||
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
|
||||
|
||||
+49
-9
@@ -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)
|
||||
@@ -98,6 +108,12 @@ func init() {
|
||||
addExample(build.APIVersion)
|
||||
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
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/node/impl"
|
||||
@@ -20,7 +20,7 @@ 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)
|
||||
n, sn := b(t, 1, OneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
|
||||
+26
-23
@@ -20,10 +20,11 @@ import (
|
||||
"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"
|
||||
sealing "github.com/filecoin-project/storage-fsm"
|
||||
dag "github.com/ipfs/go-merkledag"
|
||||
dstest "github.com/ipfs/go-merkledag/test"
|
||||
unixfile "github.com/ipfs/go-unixfs/file"
|
||||
@@ -35,7 +36,7 @@ import (
|
||||
|
||||
var MineNext = miner.MineReq{
|
||||
InjectNulls: 0,
|
||||
Done: func(bool, error) {},
|
||||
Done: func(bool, abi.ChainEpoch, error) {},
|
||||
}
|
||||
|
||||
func init() {
|
||||
@@ -47,7 +48,7 @@ func TestDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration, carExport
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, oneMiner)
|
||||
n, sn := b(t, 1, OneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
@@ -84,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]
|
||||
|
||||
@@ -141,14 +142,14 @@ func makeDeal(t *testing.T, ctx context.Context, rseed int, client *impl.FullNod
|
||||
info, err := client.ClientGetDealInfo(ctx, *deal)
|
||||
require.NoError(t, err)
|
||||
|
||||
testRetrieval(t, ctx, err, client, fcid, &info.PieceCID, carExport, data)
|
||||
testRetrieval(t, ctx, client, fcid, &info.PieceCID, carExport, data)
|
||||
}
|
||||
|
||||
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)
|
||||
n, sn := b(t, 1, OneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
@@ -193,7 +194,7 @@ func TestFastRetrievalDealFlow(t *testing.T, b APIBuilder, blocktime time.Durati
|
||||
info, err := client.ClientGetDealInfo(ctx, *deal)
|
||||
require.NoError(t, err)
|
||||
|
||||
testRetrieval(t, ctx, err, client, fcid, &info.PieceCID, false, data)
|
||||
testRetrieval(t, ctx, client, fcid, &info.PieceCID, false, data)
|
||||
atomic.AddInt64(&mine, -1)
|
||||
fmt.Println("shutting down mining")
|
||||
<-done
|
||||
@@ -203,7 +204,7 @@ func TestSenondDealRetrieval(t *testing.T, b APIBuilder, blocktime time.Duration
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, oneMiner)
|
||||
n, sn := b(t, 1, OneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
@@ -267,7 +268,7 @@ func TestSenondDealRetrieval(t *testing.T, b APIBuilder, blocktime time.Duration
|
||||
rf, _ := miner.SectorsRefs(ctx)
|
||||
fmt.Printf("refs: %+v\n", rf)
|
||||
|
||||
testRetrieval(t, ctx, err, client, fcid2, &info.PieceCID, false, data2)
|
||||
testRetrieval(t, ctx, client, fcid2, &info.PieceCID, false, data2)
|
||||
}
|
||||
|
||||
atomic.AddInt64(&mine, -1)
|
||||
@@ -333,7 +334,7 @@ loop:
|
||||
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, *deal)
|
||||
updates, err := miner.MarketGetDealUpdates(subCtx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -342,18 +343,20 @@ func waitDealPublished(t *testing.T, ctx context.Context, miner TestStorageNode,
|
||||
case <-ctx.Done():
|
||||
t.Fatal("context timeout")
|
||||
case di := <-updates:
|
||||
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
|
||||
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])
|
||||
}
|
||||
fmt.Println("Deal state: ", storagemarket.DealStates[di.State])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -373,7 +376,7 @@ func startSealingWaiting(t *testing.T, ctx context.Context, miner TestStorageNod
|
||||
}
|
||||
}
|
||||
|
||||
func testRetrieval(t *testing.T, ctx context.Context, err error, client *impl.FullNodeAPI, fcid cid.Cid, piece *cid.Cid, carExport bool, data []byte) {
|
||||
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)
|
||||
@@ -398,7 +401,7 @@ func testRetrieval(t *testing.T, ctx context.Context, err error, client *impl.Fu
|
||||
Path: filepath.Join(rpath, "ret"),
|
||||
IsCAR: carExport,
|
||||
}
|
||||
updates, err := client.ClientRetrieve(ctx, offers[0].Order(caddr), ref)
|
||||
updates, err := client.ClientRetrieveWithEvents(ctx, offers[0].Order(caddr), ref)
|
||||
for update := range updates {
|
||||
if update.Err != "" {
|
||||
t.Fatalf("%v", err)
|
||||
|
||||
+11
-12
@@ -12,7 +12,7 @@ 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"
|
||||
@@ -20,32 +20,31 @@ import (
|
||||
"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]
|
||||
|
||||
newHeads, err := api.ChainNotify(ctx)
|
||||
require.NoError(t, err)
|
||||
initHead := (<-newHeads)[0]
|
||||
if initHead.Val.Height() != 2 {
|
||||
<-newHeads
|
||||
}
|
||||
baseHeight := initHead.Val.Height()
|
||||
|
||||
h1, err := api.ChainHead(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, abi.ChainEpoch(2), h1.Height())
|
||||
require.Equal(t, int64(h1.Height()), int64(baseHeight))
|
||||
|
||||
err = sn[0].MineOne(ctx, MineNext)
|
||||
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(3), h2.Height())
|
||||
require.Greater(t, int64(h2.Height()), int64(h1.Height()))
|
||||
}
|
||||
|
||||
func (ts *testSuite) testMiningReal(t *testing.T) {
|
||||
@@ -55,7 +54,7 @@ func (ts *testSuite) testMiningReal(t *testing.T) {
|
||||
}()
|
||||
|
||||
ctx := context.Background()
|
||||
apis, sn := ts.makeNodes(t, 1, oneMiner)
|
||||
apis, sn := ts.makeNodes(t, 1, OneMiner)
|
||||
api := apis[0]
|
||||
|
||||
newHeads, err := api.ChainNotify(ctx)
|
||||
@@ -69,7 +68,7 @@ func (ts *testSuite) testMiningReal(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, abi.ChainEpoch(2), h1.Height())
|
||||
|
||||
err = sn[0].MineOne(ctx, MineNext)
|
||||
MineUntilBlock(ctx, t, apis[0], sn[0], nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
<-newHeads
|
||||
@@ -78,7 +77,7 @@ func (ts *testSuite) testMiningReal(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, abi.ChainEpoch(3), h2.Height())
|
||||
|
||||
err = sn[0].MineOne(ctx, MineNext)
|
||||
MineUntilBlock(ctx, t, apis[0], sn[0], nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
<-newHeads
|
||||
@@ -143,7 +142,7 @@ func TestDealMining(t *testing.T, b APIBuilder, blocktime time.Duration, carExpo
|
||||
complChan := minedTwo
|
||||
for atomic.LoadInt32(&mine) != 0 {
|
||||
wait := make(chan int)
|
||||
mdone := func(mined bool, err error) {
|
||||
mdone := func(mined bool, _ abi.ChainEpoch, err error) {
|
||||
n := 0
|
||||
if mined {
|
||||
n = 1
|
||||
|
||||
+19
-81
@@ -10,8 +10,8 @@ import (
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
|
||||
"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/paych"
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
@@ -23,14 +23,13 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/events/state"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
"github.com/filecoin-project/lotus/miner"
|
||||
)
|
||||
|
||||
func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 2, oneMiner)
|
||||
n, sn := b(t, 2, OneMiner)
|
||||
|
||||
paymentCreator := n[0]
|
||||
paymentReceiver := n[1]
|
||||
@@ -51,8 +50,8 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
}
|
||||
|
||||
// start mining blocks
|
||||
bm := newBlockMiner(ctx, t, miner, blocktime)
|
||||
bm.mineBlocks()
|
||||
bm := NewBlockMiner(ctx, t, miner, blocktime)
|
||||
bm.MineBlocks()
|
||||
|
||||
// send some funds to register the receiver
|
||||
receiverAddr, err := paymentReceiver.WalletNew(ctx, wallet.ActSigType("secp256k1"))
|
||||
@@ -60,7 +59,7 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sendFunds(ctx, t, paymentCreator, receiverAddr, abi.NewTokenAmount(1e18))
|
||||
SendFunds(ctx, t, paymentCreator, receiverAddr, abi.NewTokenAmount(1e18))
|
||||
|
||||
// setup the payment channel
|
||||
createrAddr, err := paymentCreator.WalletDefaultAddress(ctx)
|
||||
@@ -97,18 +96,24 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
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)
|
||||
}
|
||||
delta1, err := paymentReceiver.PaychVoucherAdd(ctx, channel, vouch1, nil, abi.NewTokenAmount(1000))
|
||||
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, nil, abi.NewTokenAmount(1000))
|
||||
delta2, err := paymentReceiver.PaychVoucherAdd(ctx, channel, vouch2.Voucher, nil, abi.NewTokenAmount(1000))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -154,6 +159,9 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
}, 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:
|
||||
@@ -201,10 +209,10 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
}
|
||||
|
||||
// shut down mining
|
||||
bm.stop()
|
||||
bm.Stop()
|
||||
}
|
||||
|
||||
func waitForBlocks(ctx context.Context, t *testing.T, bm *blockMiner, paymentReceiver TestNode, receiverAddr address.Address, count int) {
|
||||
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 {
|
||||
@@ -249,73 +257,3 @@ func waitForMessage(ctx context.Context, t *testing.T, paymentCreator TestNode,
|
||||
fmt.Println("Confirmed", desc)
|
||||
return res
|
||||
}
|
||||
|
||||
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, error) {},
|
||||
}); err != nil {
|
||||
bm.t.Error(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (bm *blockMiner) stop() {
|
||||
atomic.AddInt64(&bm.mine, -1)
|
||||
fmt.Println("shutting down mining")
|
||||
<-bm.done
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
+12
-4
@@ -4,6 +4,8 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
@@ -14,10 +16,16 @@ import (
|
||||
|
||||
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, miner.MineReq) error
|
||||
}
|
||||
@@ -54,11 +62,11 @@ 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) {
|
||||
ctx := context.Background()
|
||||
apis, _ := ts.makeNodes(t, 1, oneMiner)
|
||||
apis, _ := ts.makeNodes(t, 1, OneMiner)
|
||||
api := apis[0]
|
||||
|
||||
v, err := api.Version(ctx)
|
||||
@@ -70,7 +78,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)
|
||||
@@ -82,7 +90,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...")
|
||||
}
|
||||
+17
-10
@@ -12,10 +12,10 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/sector-storage/mock"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"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"
|
||||
@@ -24,11 +24,16 @@ import (
|
||||
"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]
|
||||
|
||||
@@ -48,7 +53,7 @@ func TestPledgeSector(t *testing.T, b APIBuilder, blocktime time.Duration, nSect
|
||||
defer close(done)
|
||||
for mine {
|
||||
build.Clock.Sleep(blocktime)
|
||||
if err := sn[0].MineOne(ctx, bminer.MineReq{Done: func(bool, error) {
|
||||
if err := sn[0].MineOne(ctx, bminer.MineReq{Done: func(bool, abi.ChainEpoch, error) {
|
||||
|
||||
}}); err != nil {
|
||||
t.Error(err)
|
||||
@@ -110,10 +115,8 @@ func pledgeSectors(t *testing.T, ctx context.Context, miner TestStorageNode, n,
|
||||
}
|
||||
|
||||
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]
|
||||
|
||||
@@ -213,6 +216,10 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector
|
||||
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),
|
||||
|
||||
+70
-12
@@ -2,10 +2,14 @@ package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
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"
|
||||
@@ -46,11 +50,12 @@ type PubsubScore struct {
|
||||
}
|
||||
|
||||
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
|
||||
@@ -58,12 +63,20 @@ type MinerInfo struct {
|
||||
}
|
||||
|
||||
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,
|
||||
@@ -83,7 +96,8 @@ type MessageSendSpec struct {
|
||||
}
|
||||
|
||||
var DefaultMessageSendSpec = MessageSendSpec{
|
||||
MaxFee: big.Zero(),
|
||||
// MaxFee of 0.1FIL
|
||||
MaxFee: abi.NewTokenAmount(int64(build.FilecoinPrecision) / 10),
|
||||
}
|
||||
|
||||
func (ms *MessageSendSpec) Get() MessageSendSpec {
|
||||
@@ -93,3 +107,47 @@ func (ms *MessageSendSpec) Get() MessageSendSpec {
|
||||
|
||||
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)
|
||||
|
||||
@@ -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
|
||||
|
||||
+15
-1
@@ -2,7 +2,7 @@ package build
|
||||
|
||||
import "github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
|
||||
var DrandNetwork = DrandMainnet
|
||||
var DrandNetwork = DrandIncentinet
|
||||
|
||||
func DrandConfig() dtypes.DrandConfig {
|
||||
return DrandConfigs[DrandNetwork]
|
||||
@@ -15,6 +15,7 @@ const (
|
||||
DrandTestnet
|
||||
DrandDevnet
|
||||
DrandLocalnet
|
||||
DrandIncentinet
|
||||
)
|
||||
|
||||
var DrandConfigs = map[DrandEnum]dtypes.DrandConfig{
|
||||
@@ -55,4 +56,17 @@ var DrandConfigs = map[DrandEnum]dtypes.DrandConfig{
|
||||
},
|
||||
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.
+5
-2
@@ -3,13 +3,16 @@
|
||||
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 = 0
|
||||
const BreezeGasTampingDuration = 0
|
||||
|
||||
func init() {
|
||||
power.ConsensusMinerMinPower = big.NewInt(2048)
|
||||
miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -5,7 +5,7 @@ package build
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"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"
|
||||
)
|
||||
@@ -89,11 +89,14 @@ const VerifSigCacheSize = 32000
|
||||
|
||||
// TODO: If this is gonna stay, it should move to specs-actors
|
||||
const BlockMessageLimit = 10000
|
||||
|
||||
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
|
||||
|
||||
@@ -10,7 +10,7 @@ package build
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"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"
|
||||
)
|
||||
@@ -66,4 +66,10 @@ var (
|
||||
// Actor consts
|
||||
// TODO: Pull from actors when its made not private
|
||||
MinDealDuration = abi.ChainEpoch(180 * builtin.EpochsInDay)
|
||||
|
||||
PackingEfficiencyNum int64 = 4
|
||||
PackingEfficiencyDenom int64 = 5
|
||||
|
||||
UpgradeBreezeHeight abi.ChainEpoch = 0
|
||||
BreezeGasTampingDuration abi.ChainEpoch = 0
|
||||
)
|
||||
|
||||
@@ -5,15 +5,18 @@
|
||||
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"
|
||||
)
|
||||
|
||||
const UpgradeBreezeHeight = 41280
|
||||
const BreezeGasTampingDuration = 120
|
||||
|
||||
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: {},
|
||||
|
||||
+2
-2
@@ -25,7 +25,7 @@ func buildType() string {
|
||||
}
|
||||
|
||||
// BuildVersion is the local build version, set by build system
|
||||
const BuildVersion = "0.4.4"
|
||||
const BuildVersion = "0.6.2-rc1"
|
||||
|
||||
func UserVersion() string {
|
||||
return BuildVersion + buildType() + CurrentCommit
|
||||
@@ -53,7 +53,7 @@ func (ve Version) EqMajorMinor(v2 Version) bool {
|
||||
}
|
||||
|
||||
// APIVersion is a semver version of the rpc api exposed
|
||||
var APIVersion Version = newVer(0, 10, 0)
|
||||
var APIVersion Version = 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"
|
||||
)
|
||||
|
||||
@@ -3,7 +3,7 @@ package beacon
|
||||
import (
|
||||
"context"
|
||||
|
||||
"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"
|
||||
|
||||
@@ -37,6 +37,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)
|
||||
|
||||
@@ -19,7 +19,7 @@ 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"
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
|
||||
"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 {
|
||||
|
||||
@@ -6,8 +6,8 @@ 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"
|
||||
)
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
inet "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"
|
||||
@@ -36,12 +37,13 @@ type BlockSync struct {
|
||||
}
|
||||
|
||||
func NewClient(
|
||||
lc fx.Lifecycle,
|
||||
host host.Host,
|
||||
pmgr peermgr.MaybePeerMgr,
|
||||
) *BlockSync {
|
||||
return &BlockSync{
|
||||
host: host,
|
||||
peerTracker: newPeerTracker(pmgr.Mgr),
|
||||
peerTracker: newPeerTracker(lc, host, pmgr.Mgr),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,7 +174,7 @@ func (client *BlockSync) processResponse(
|
||||
resLength, req.Length)
|
||||
}
|
||||
if resLength < int(req.Length) && res.Status != Partial {
|
||||
return nil, xerrors.Errorf("got less than requested without a proper status: %s", res.Status)
|
||||
return nil, xerrors.Errorf("got less than requested without a proper status: %d", res.Status)
|
||||
}
|
||||
|
||||
validRes := &validatedResponse{}
|
||||
@@ -205,7 +207,7 @@ func (client *BlockSync) processResponse(
|
||||
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): %w", i)
|
||||
return nil, xerrors.Errorf("no messages included for tipset at height (head - %d)", i)
|
||||
}
|
||||
validRes.messages[i] = res.Chain[i].Messages
|
||||
}
|
||||
@@ -308,6 +310,12 @@ func (client *BlockSync) GetChainMessages(
|
||||
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{
|
||||
@@ -354,6 +362,7 @@ func (client *BlockSync) sendRequestToPeer(
|
||||
|
||||
supported, err := client.host.Peerstore().SupportsProtocols(peer, BlockSyncProtocolID)
|
||||
if err != nil {
|
||||
client.RemovePeer(peer)
|
||||
return nil, xerrors.Errorf("failed to get protocols for peer: %w", err)
|
||||
}
|
||||
if len(supported) == 0 || supported[0] != BlockSyncProtocolID {
|
||||
@@ -379,7 +388,7 @@ func (client *BlockSync) sendRequestToPeer(
|
||||
_ = stream.SetWriteDeadline(time.Now().Add(WRITE_REQ_DEADLINE))
|
||||
if err := cborutil.WriteCborRPC(stream, req); err != nil {
|
||||
_ = stream.SetWriteDeadline(time.Time{})
|
||||
client.peerTracker.logFailure(peer, build.Clock.Since(connectionStart))
|
||||
client.peerTracker.logFailure(peer, build.Clock.Since(connectionStart), req.Length)
|
||||
// FIXME: Should we also remove peer here?
|
||||
return nil, err
|
||||
}
|
||||
@@ -392,7 +401,7 @@ func (client *BlockSync) sendRequestToPeer(
|
||||
bufio.NewReader(incrt.New(stream, READ_RES_MIN_SPEED, READ_RES_DEADLINE)),
|
||||
&res)
|
||||
if err != nil {
|
||||
client.peerTracker.logFailure(peer, build.Clock.Since(connectionStart))
|
||||
client.peerTracker.logFailure(peer, build.Clock.Since(connectionStart), req.Length)
|
||||
return nil, xerrors.Errorf("failed to read blocksync response: %w", err)
|
||||
}
|
||||
|
||||
@@ -406,7 +415,7 @@ func (client *BlockSync) sendRequestToPeer(
|
||||
)
|
||||
}
|
||||
|
||||
client.peerTracker.logSuccess(peer, build.Clock.Since(connectionStart))
|
||||
client.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
|
||||
|
||||
@@ -3,11 +3,14 @@ package blocksync
|
||||
// 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"
|
||||
@@ -29,11 +32,30 @@ type bsPeerTracker struct {
|
||||
pmgr *peermgr.PeerMgr
|
||||
}
|
||||
|
||||
func newPeerTracker(pmgr *peermgr.PeerMgr) *bsPeerTracker {
|
||||
return &bsPeerTracker{
|
||||
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) {
|
||||
@@ -72,16 +94,7 @@ func (bpt *bsPeerTracker) prefSortedPeers() []peer.ID {
|
||||
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
|
||||
return float64(bpt.avgGlobalTime) * newPeerMul
|
||||
}
|
||||
|
||||
if pi.successes+pi.failures > 0 {
|
||||
@@ -107,8 +120,8 @@ func (bpt *bsPeerTracker) prefSortedPeers() []peer.ID {
|
||||
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
|
||||
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) {
|
||||
@@ -133,7 +146,7 @@ func logTime(pi *peerStats, dur time.Duration) {
|
||||
|
||||
}
|
||||
|
||||
func (bpt *bsPeerTracker) logSuccess(p peer.ID, dur time.Duration) {
|
||||
func (bpt *bsPeerTracker) logSuccess(p peer.ID, dur time.Duration, reqSize uint64) {
|
||||
bpt.lk.Lock()
|
||||
defer bpt.lk.Unlock()
|
||||
|
||||
@@ -145,10 +158,13 @@ func (bpt *bsPeerTracker) logSuccess(p peer.ID, dur time.Duration) {
|
||||
}
|
||||
|
||||
pi.successes++
|
||||
logTime(pi, dur)
|
||||
if reqSize == 0 {
|
||||
reqSize = 1
|
||||
}
|
||||
logTime(pi, dur/time.Duration(reqSize))
|
||||
}
|
||||
|
||||
func (bpt *bsPeerTracker) logFailure(p peer.ID, dur time.Duration) {
|
||||
func (bpt *bsPeerTracker) logFailure(p peer.ID, dur time.Duration, reqSize uint64) {
|
||||
bpt.lk.Lock()
|
||||
defer bpt.lk.Unlock()
|
||||
|
||||
@@ -160,7 +176,10 @@ func (bpt *bsPeerTracker) logFailure(p peer.ID, dur time.Duration) {
|
||||
}
|
||||
|
||||
pi.failures++
|
||||
logTime(pi, dur)
|
||||
if reqSize == 0 {
|
||||
reqSize = 1
|
||||
}
|
||||
logTime(pi, dur/time.Duration(reqSize))
|
||||
}
|
||||
|
||||
func (bpt *bsPeerTracker) removePeer(p peer.ID) {
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package blocksync
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"time"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
logging "github.com/ipfs/go-log"
|
||||
|
||||
+24
-15
@@ -221,37 +221,36 @@ func collectChainSegment(
|
||||
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
|
||||
|
||||
var blscids, secpkcids []cid.Cid
|
||||
for _, block := range ts.Blocks() {
|
||||
bmsgs, smsgs, err := cs.MessagesForBlock(block)
|
||||
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(bmsgs))
|
||||
for _, m := range bmsgs {
|
||||
i, ok := blsmsgmap[m.Cid()]
|
||||
bmi := make([]uint64, 0, len(bc))
|
||||
for _, m := range bc {
|
||||
i, ok := blsmsgmap[m]
|
||||
if !ok {
|
||||
i = uint64(len(blsmsgs))
|
||||
blsmsgs = append(blsmsgs, m)
|
||||
blsmsgmap[m.Cid()] = i
|
||||
i = uint64(len(blscids))
|
||||
blscids = append(blscids, m)
|
||||
blsmsgmap[m] = i
|
||||
}
|
||||
|
||||
bmi = append(bmi, i)
|
||||
}
|
||||
blsincl = append(blsincl, bmi)
|
||||
|
||||
smi := make([]uint64, 0, len(smsgs))
|
||||
for _, m := range smsgs {
|
||||
i, ok := secpkmsgmap[m.Cid()]
|
||||
smi := make([]uint64, 0, len(sc))
|
||||
for _, m := range sc {
|
||||
i, ok := secpkmsgmap[m]
|
||||
if !ok {
|
||||
i = uint64(len(secpkmsgs))
|
||||
secpkmsgs = append(secpkmsgs, m)
|
||||
secpkmsgmap[m.Cid()] = i
|
||||
i = uint64(len(secpkcids))
|
||||
secpkcids = append(secpkcids, m)
|
||||
secpkmsgmap[m] = i
|
||||
}
|
||||
|
||||
smi = append(smi, i)
|
||||
@@ -259,5 +258,15 @@ func gatherMessages(cs *store.ChainStore, ts *types.TipSet) ([]*types.Message, [
|
||||
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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -2,6 +2,7 @@ package state
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
typegen "github.com/whyrusleeping/cbor-gen"
|
||||
)
|
||||
|
||||
@@ -3,9 +3,10 @@ package state
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"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"
|
||||
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/market"
|
||||
|
||||
@@ -13,11 +13,11 @@ import (
|
||||
cbornode "github.com/ipfs/go-ipld-cbor"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"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"
|
||||
|
||||
@@ -114,10 +114,10 @@ func TestMarketPredicates(t *testing.T) {
|
||||
}
|
||||
|
||||
oldBalances := map[address.Address]balance{
|
||||
tutils.NewIDAddr(t, 1): balance{abi.NewTokenAmount(1000), abi.NewTokenAmount(1000)},
|
||||
tutils.NewIDAddr(t, 2): balance{abi.NewTokenAmount(2000), abi.NewTokenAmount(500)},
|
||||
tutils.NewIDAddr(t, 3): balance{abi.NewTokenAmount(3000), abi.NewTokenAmount(2000)},
|
||||
tutils.NewIDAddr(t, 5): balance{abi.NewTokenAmount(3000), abi.NewTokenAmount(1000)},
|
||||
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)
|
||||
@@ -162,10 +162,10 @@ func TestMarketPredicates(t *testing.T) {
|
||||
// NB: DealProposals cannot be modified, so don't test that case.
|
||||
}
|
||||
newBalances := map[address.Address]balance{
|
||||
tutils.NewIDAddr(t, 1): balance{abi.NewTokenAmount(3000), abi.NewTokenAmount(0)},
|
||||
tutils.NewIDAddr(t, 2): balance{abi.NewTokenAmount(2000), abi.NewTokenAmount(500)},
|
||||
tutils.NewIDAddr(t, 4): balance{abi.NewTokenAmount(5000), abi.NewTokenAmount(0)},
|
||||
tutils.NewIDAddr(t, 5): balance{abi.NewTokenAmount(1000), abi.NewTokenAmount(3000)},
|
||||
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)
|
||||
@@ -505,6 +505,7 @@ func createBalanceTable(ctx context.Context, t *testing.T, store adt.Store, bala
|
||||
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))
|
||||
@@ -542,6 +543,7 @@ func createEmptyMinerState(ctx context.Context, t *testing.T, store adt.Store, o
|
||||
|
||||
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)
|
||||
|
||||
+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)
|
||||
}
|
||||
|
||||
+36
-21
@@ -8,11 +8,13 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime/proof"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"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"
|
||||
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"
|
||||
@@ -34,18 +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"),
|
||||
}}
|
||||
|
||||
@@ -92,10 +95,8 @@ func (m mybs) Get(c cid.Cid) (block.Block, error) {
|
||||
return b, nil
|
||||
}
|
||||
|
||||
var rootkey, _ = address.NewIDAddress(80)
|
||||
|
||||
var rootkeyMultisig = genesis.MultisigMeta{
|
||||
Signers: []address.Address{rootkey},
|
||||
Signers: []address.Address{remAccTestKey},
|
||||
Threshold: 1,
|
||||
VestingDuration: 0,
|
||||
VestingStart: 0,
|
||||
@@ -107,6 +108,18 @@ var DefaultVerifregRootkeyActor = genesis.Actor{
|
||||
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: {},
|
||||
@@ -210,9 +223,10 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
||||
*genm1,
|
||||
*genm2,
|
||||
},
|
||||
VerifregRootKey: DefaultVerifregRootkeyActor,
|
||||
NetworkName: "",
|
||||
Timestamp: uint64(build.Clock.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)
|
||||
@@ -304,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().Codec == cid.FilCommitmentSealed || link.Cid.Prefix().Codec == cid.FilCommitmentUnsealed {
|
||||
pref := link.Cid.Prefix()
|
||||
if pref.Codec == cid.FilCommitmentSealed || pref.Codec == cid.FilCommitmentUnsealed {
|
||||
continue
|
||||
}
|
||||
out = append(out, link)
|
||||
@@ -444,7 +459,7 @@ func (cg *ChainGen) NextTipSetFromMinersWithMessages(base *types.TipSet, miners
|
||||
|
||||
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 {
|
||||
@@ -575,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{}
|
||||
@@ -584,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
|
||||
}
|
||||
|
||||
@@ -593,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())
|
||||
@@ -651,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"
|
||||
|
||||
@@ -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
|
||||
}
|
||||
+191
-77
@@ -2,7 +2,11 @@ package genesis
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-datastore"
|
||||
@@ -12,13 +16,13 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
|
||||
"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"
|
||||
"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/crypto"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
@@ -117,11 +121,6 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
|
||||
return nil, nil, xerrors.Errorf("making new state tree: %w", err)
|
||||
}
|
||||
|
||||
emptyobject, err := cst.Put(context.TODO(), []struct{}{})
|
||||
if err != nil {
|
||||
return nil, nil, xerrors.Errorf("failed putting empty object: %w", err)
|
||||
}
|
||||
|
||||
// Create system actor
|
||||
|
||||
sysact, err := SetupSystemActor(bs)
|
||||
@@ -134,7 +133,7 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
|
||||
|
||||
// Create init actor
|
||||
|
||||
initact, keyIDs, err := SetupInitActor(bs, template.NetworkName, template.Accounts, template.VerifregRootKey)
|
||||
idStart, initact, keyIDs, err := SetupInitActor(bs, template.NetworkName, template.Accounts, template.VerifregRootKey)
|
||||
if err != nil {
|
||||
return nil, nil, xerrors.Errorf("setup init actor: %w", err)
|
||||
}
|
||||
@@ -190,31 +189,47 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
|
||||
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, nil, xerrors.Errorf("set burnt funds account actor: %w", err)
|
||||
}
|
||||
|
||||
// Create accounts
|
||||
for id, info := range template.Accounts {
|
||||
if info.Type != genesis.TAccount && info.Type != genesis.TMultisig {
|
||||
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, nil, err
|
||||
}
|
||||
|
||||
if err = createAccount(ctx, bs, cst, state, ida, info); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
vregroot, err := address.NewIDAddress(80)
|
||||
@@ -222,8 +237,8 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if err = createAccount(ctx, bs, cst, state, vregroot, template.VerifregRootKey); err != nil {
|
||||
return nil, nil, err
|
||||
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
|
||||
@@ -258,63 +273,132 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
|
||||
Balance: types.NewInt(0),
|
||||
Head: verifierState,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, xerrors.Errorf("setting account from actmap: %w", err)
|
||||
}
|
||||
|
||||
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 createAccount(ctx context.Context, bs bstore.Blockstore, cst cbor.IpldStore, state *state.StateTree, ida address.Address, info genesis.Actor) error {
|
||||
if info.Type == genesis.TAccount {
|
||||
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
|
||||
}
|
||||
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)
|
||||
}
|
||||
} else if info.Type == genesis.TMultisig {
|
||||
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)
|
||||
}
|
||||
|
||||
st, err := cst.Put(ctx, &multisig.State{
|
||||
Signers: ainfo.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)
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
@@ -322,6 +406,10 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot ci
|
||||
verifNeeds := make(map[address.Address]abi.PaddedPieceSize)
|
||||
var sum abi.PaddedPieceSize
|
||||
|
||||
nwv := func(context.Context, abi.ChainEpoch) runtime.NetworkVersion {
|
||||
return runtime.NetworkVersion1
|
||||
}
|
||||
|
||||
vmopt := vm.VMOpts{
|
||||
StateBase: stateroot,
|
||||
Epoch: 0,
|
||||
@@ -329,6 +417,7 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot ci
|
||||
Bstore: cs.Blockstore(),
|
||||
Syscalls: mkFakedSigSyscalls(cs.VMSys()),
|
||||
CircSupplyCalc: nil,
|
||||
NtwkVersion: nwv,
|
||||
BaseFee: types.NewInt(0),
|
||||
}
|
||||
vm, err := vm.NewVM(&vmopt)
|
||||
@@ -336,11 +425,12 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot ci
|
||||
return cid.Undef, xerrors.Errorf("failed to create NewVM: %w", err)
|
||||
}
|
||||
|
||||
for _, m := range template.Miners {
|
||||
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)
|
||||
}
|
||||
|
||||
// Add the miner to the market actor's balance table
|
||||
_, err = doExec(ctx, vm, builtin.StorageMarketActorAddr, m.Owner, builtin.MethodsMarket.AddBalance, mustEnc(adt.Empty))
|
||||
for _, s := range m.Sectors {
|
||||
amt := s.Deal.PieceSize
|
||||
verifNeeds[keyIDs[s.Deal.Client]] += amt
|
||||
sum += amt
|
||||
@@ -430,14 +520,38 @@ func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys vm.SyscallB
|
||||
|
||||
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,
|
||||
|
||||
+25
-10
@@ -14,15 +14,15 @@ import (
|
||||
"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/builtin/reward"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
@@ -61,6 +61,10 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
return big.Zero(), nil
|
||||
}
|
||||
|
||||
nwv := func(context.Context, abi.ChainEpoch) runtime.NetworkVersion {
|
||||
return runtime.NetworkVersion1
|
||||
}
|
||||
|
||||
vmopt := &vm.VMOpts{
|
||||
StateBase: sroot,
|
||||
Epoch: 0,
|
||||
@@ -68,6 +72,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
Bstore: cs.Blockstore(),
|
||||
Syscalls: mkFakedSigSyscalls(cs.VMSys()),
|
||||
CircSupplyCalc: csc,
|
||||
NtwkVersion: nwv,
|
||||
BaseFee: types.NewInt(0),
|
||||
}
|
||||
|
||||
@@ -129,6 +134,9 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("mutating state: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Add market funds
|
||||
@@ -137,7 +145,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
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)
|
||||
return cid.Undef, xerrors.Errorf("failed to create genesis miner (add balance): %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,7 +157,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
|
||||
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 {
|
||||
@@ -217,9 +225,12 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
}
|
||||
|
||||
err = vm.MutateState(ctx, builtin.RewardActorAddr, func(sct cbor.IpldStore, st *reward.State) error {
|
||||
st = reward.ConstructState(qaPow)
|
||||
*st = *reward.ConstructState(qaPow)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("mutating state: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
for i, m := range miners {
|
||||
@@ -244,7 +255,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
|
||||
// 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)
|
||||
st.TotalQualityAdjPower = types.BigSub(st.TotalQualityAdjPower, sectorWeight) //nolint:scopelint
|
||||
st.TotalRawBytePower = types.BigSub(st.TotalRawBytePower, types.NewInt(uint64(m.SectorSize)))
|
||||
return nil
|
||||
})
|
||||
@@ -262,6 +273,8 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
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,
|
||||
@@ -271,6 +284,8 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
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 {
|
||||
@@ -320,13 +335,13 @@ type fakeRand struct{}
|
||||
|
||||
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 * 1000))).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)
|
||||
_, _ = rand.New(rand.NewSource(int64(randEpoch))).Read(out) //nolint
|
||||
return out, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
@@ -19,9 +20,9 @@ import (
|
||||
bstore "github.com/filecoin-project/lotus/lib/blockstore"
|
||||
)
|
||||
|
||||
func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesis.Actor, rootVerifier genesis.Actor) (*types.Actor, map[address.Address]address.Address, 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, nil, xerrors.New("too many initial actors")
|
||||
return 0, nil, nil, xerrors.New("too many initial actors")
|
||||
}
|
||||
|
||||
var ias init_.State
|
||||
@@ -32,55 +33,105 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi
|
||||
amap := adt.MakeEmptyMap(store)
|
||||
|
||||
keyToId := map[address.Address]address.Address{}
|
||||
counter := int64(AccountStart)
|
||||
|
||||
for i, a := range initialActors {
|
||||
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
|
||||
}
|
||||
|
||||
if a.Type != genesis.TAccount {
|
||||
return nil, 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, 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+int64(i))
|
||||
fmt.Printf("init set %s t0%d\n", ainfo.Owner, counter)
|
||||
|
||||
value := cbg.CborInt(AccountStart + int64(i))
|
||||
value := cbg.CborInt(counter)
|
||||
if err := amap.Put(adt.AddrKey(ainfo.Owner), &value); err != nil {
|
||||
return nil, nil, err
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
counter = counter + 1
|
||||
|
||||
var err error
|
||||
keyToId[ainfo.Owner], err = address.NewIDAddress(uint64(value))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if rootVerifier.Type == genesis.TAccount {
|
||||
var ainfo genesis.AccountMeta
|
||||
if err := json.Unmarshal(rootVerifier.Meta, &ainfo); err != nil {
|
||||
return nil, nil, xerrors.Errorf("unmarshaling account meta: %w", err)
|
||||
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 nil, nil, err
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
amapaddr, err := amap.Root()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
ias.AddressMap = amapaddr
|
||||
|
||||
statecid, err := store.Put(store.Context(), &ias)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
|
||||
act := &types.Actor{
|
||||
@@ -88,5 +139,5 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi
|
||||
Head: statecid,
|
||||
}
|
||||
|
||||
return act, keyToId, nil
|
||||
return counter, act, keyToId, nil
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package genesis
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"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"
|
||||
|
||||
@@ -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{
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ package gen
|
||||
import (
|
||||
"context"
|
||||
|
||||
"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"
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
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"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
)
|
||||
|
||||
type SlashFilter struct {
|
||||
|
||||
+18
-11
@@ -4,8 +4,8 @@ import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"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"
|
||||
"go.uber.org/fx"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/events"
|
||||
"github.com/filecoin-project/lotus/chain/events/state"
|
||||
@@ -52,7 +51,7 @@ func StartFundManager(lc fx.Lifecycle, api API) *FundMgr {
|
||||
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, int(build.MessageConfidence), events.NoTimeout, match)
|
||||
return ev.StateChanged(fm.checkFunc, fm.stateChanged, fm.revert, 0, events.NoTimeout, match)
|
||||
},
|
||||
})
|
||||
return fm
|
||||
@@ -92,6 +91,10 @@ func (fm *FundMgr) stateChanged(ts *types.TipSet, ts2 *types.TipSet, states even
|
||||
// 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())
|
||||
}
|
||||
|
||||
fm.available[addr] = balanceChange.To
|
||||
}
|
||||
fm.lk.Unlock()
|
||||
@@ -116,15 +119,17 @@ func (fm *FundMgr) EnsureAvailable(ctx context.Context, addr, wallet address.Add
|
||||
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
|
||||
}
|
||||
|
||||
stateAvail := types.BigSub(bal.Escrow, bal.Locked)
|
||||
|
||||
avail, ok := fm.available[idAddr]
|
||||
if !ok {
|
||||
bal, err := fm.api.StateMarketBalance(ctx, addr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
fm.lk.Unlock()
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
avail = types.BigSub(bal.Escrow, bal.Locked)
|
||||
avail = stateAvail
|
||||
}
|
||||
|
||||
toAdd := types.BigSub(amt, avail)
|
||||
@@ -134,6 +139,8 @@ func (fm *FundMgr) EnsureAvailable(ctx context.Context, addr, wallet address.Add
|
||||
fm.available[idAddr] = big.Add(avail, toAdd)
|
||||
fm.lk.Unlock()
|
||||
|
||||
log.Infof("Funds operation w/ Expected Balance: %s, In State: %s, Requested: %s, Adding: %s", avail.String(), stateAvail.String(), amt.String(), toAdd.String())
|
||||
|
||||
if toAdd.LessThanEqual(big.Zero()) {
|
||||
return cid.Undef, nil
|
||||
}
|
||||
|
||||
@@ -10,9 +10,9 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
tutils "github.com/filecoin-project/specs-actors/support/testing"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
@@ -147,6 +147,7 @@ func TestAddFunds(t *testing.T) {
|
||||
}
|
||||
|
||||
for testCase, data := range testCases {
|
||||
//nolint:scopelint
|
||||
t.Run(testCase, func(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
@@ -26,6 +26,28 @@ func noWinnersProb() []float64 {
|
||||
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()
|
||||
@@ -34,13 +56,13 @@ func binomialCoefficient(n, k float64) float64 {
|
||||
for d := 1.0; d <= k; d++ {
|
||||
r *= n
|
||||
r /= d
|
||||
n -= 1
|
||||
n--
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (mp *MessagePool) blockProbabilities(tq float64) []float64 {
|
||||
noWinners := noWinnersProb() // cache this
|
||||
noWinners := noWinnersProbAssumingMoreThanOne()
|
||||
|
||||
p := 1 - tq
|
||||
binoPdf := func(x, trials float64) float64 {
|
||||
@@ -72,7 +94,7 @@ func (mp *MessagePool) blockProbabilities(tq float64) []float64 {
|
||||
for place := 0; place < MaxBlocks; place++ {
|
||||
var pPlace float64
|
||||
for otherWinners, pCase := range noWinners {
|
||||
pPlace += pCase * binoPdf(float64(place), float64(otherWinners+1))
|
||||
pPlace += pCase * binoPdf(float64(place), float64(otherWinners))
|
||||
}
|
||||
out = append(out, pPlace)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
package messagepool
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"math"
|
||||
"math/rand"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestBlockProbability(t *testing.T) {
|
||||
mp := &MessagePool{}
|
||||
@@ -13,3 +18,26 @@ func TestBlockProbability(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
)
|
||||
|
||||
|
||||
+496
-127
@@ -6,12 +6,13 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
stdbig "math/big"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-datastore"
|
||||
@@ -26,6 +27,7 @@ import (
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"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/lib/sigs"
|
||||
@@ -36,14 +38,21 @@ import (
|
||||
|
||||
var log = logging.Logger("messagepool")
|
||||
|
||||
const futureDebug = false
|
||||
var futureDebug = false
|
||||
|
||||
var rbfNumBig = types.NewInt(uint64((ReplaceByFeeRatioDefault - 1) * RbfDenom))
|
||||
var rbfDenomBig = types.NewInt(RbfDenom)
|
||||
|
||||
const RbfDenom = 256
|
||||
|
||||
var RepublishInterval = pubsub.TimeCacheDuration + time.Duration(5*build.BlockDelaySecs+build.PropagationDelaySecs)*time.Second
|
||||
var RepublishInterval = time.Duration(10*build.BlockDelaySecs+build.PropagationDelaySecs) * time.Second
|
||||
|
||||
var minimumBaseFee = types.NewInt(uint64(build.MinimumBaseFee))
|
||||
var baseFeeLowerBoundFactor = types.NewInt(10)
|
||||
|
||||
var MaxActorPendingMessages = 1000
|
||||
|
||||
var MaxNonceGap = uint64(4)
|
||||
|
||||
var (
|
||||
ErrMessageTooBig = errors.New("message too big")
|
||||
@@ -52,14 +61,18 @@ var (
|
||||
|
||||
ErrNonceTooLow = errors.New("message nonce too low")
|
||||
|
||||
ErrGasFeeCapTooLow = errors.New("gas fee cap too low")
|
||||
|
||||
ErrNotEnoughFunds = errors.New("not enough funds to execute transaction")
|
||||
|
||||
ErrInvalidToAddr = errors.New("message had invalid to address")
|
||||
|
||||
ErrBroadcastAnyway = errors.New("broadcasting message despite validation fail")
|
||||
ErrRBFTooLowPremium = errors.New("replace by fee has too low GasPremium")
|
||||
ErrSoftValidationFailure = errors.New("validation failure")
|
||||
ErrRBFTooLowPremium = errors.New("replace by fee has too low GasPremium")
|
||||
ErrTooManyPendingMessages = errors.New("too many pending messages for actor")
|
||||
ErrNonceGap = errors.New("unfulfilled nonce gap")
|
||||
|
||||
ErrTryAgain = errors.New("state inconsistency while signing message; please try again")
|
||||
ErrTryAgain = errors.New("state inconsistency while pushing message; please try again")
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -68,6 +81,18 @@ const (
|
||||
localUpdates = "update"
|
||||
)
|
||||
|
||||
// this is *temporary* mutilation until we have implemented uncapped miner penalties -- it will go
|
||||
// away in the next fork.
|
||||
var strictBaseFeeValidation = false
|
||||
|
||||
func init() {
|
||||
// if the republish interval is too short compared to the pubsub timecache, adjust it
|
||||
minInterval := pubsub.TimeCacheDuration + time.Duration(build.PropagationDelaySecs)
|
||||
if RepublishInterval < minInterval {
|
||||
RepublishInterval = minInterval
|
||||
}
|
||||
}
|
||||
|
||||
type MessagePool struct {
|
||||
lk sync.Mutex
|
||||
|
||||
@@ -75,8 +100,12 @@ type MessagePool struct {
|
||||
|
||||
addSema chan struct{}
|
||||
|
||||
closer chan struct{}
|
||||
repubTk *clock.Ticker
|
||||
closer chan struct{}
|
||||
|
||||
repubTk *clock.Ticker
|
||||
repubTrigger chan struct{}
|
||||
|
||||
republished map[cid.Cid]struct{}
|
||||
|
||||
localAddrs map[address.Address]struct{}
|
||||
|
||||
@@ -112,22 +141,44 @@ type MessagePool struct {
|
||||
}
|
||||
|
||||
type msgSet struct {
|
||||
msgs map[uint64]*types.SignedMessage
|
||||
nextNonce uint64
|
||||
msgs map[uint64]*types.SignedMessage
|
||||
nextNonce uint64
|
||||
requiredFunds *stdbig.Int
|
||||
}
|
||||
|
||||
func newMsgSet() *msgSet {
|
||||
func newMsgSet(nonce uint64) *msgSet {
|
||||
return &msgSet{
|
||||
msgs: make(map[uint64]*types.SignedMessage),
|
||||
msgs: make(map[uint64]*types.SignedMessage),
|
||||
nextNonce: nonce,
|
||||
requiredFunds: stdbig.NewInt(0),
|
||||
}
|
||||
}
|
||||
|
||||
func (ms *msgSet) add(m *types.SignedMessage, mp *MessagePool) (bool, error) {
|
||||
if len(ms.msgs) == 0 || m.Message.Nonce >= ms.nextNonce {
|
||||
ms.nextNonce = m.Message.Nonce + 1
|
||||
func (ms *msgSet) add(m *types.SignedMessage, mp *MessagePool, strict bool) (bool, error) {
|
||||
nextNonce := ms.nextNonce
|
||||
nonceGap := false
|
||||
switch {
|
||||
case m.Message.Nonce == nextNonce:
|
||||
nextNonce++
|
||||
// advance if we are filling a gap
|
||||
for _, fillGap := ms.msgs[nextNonce]; fillGap; _, fillGap = ms.msgs[nextNonce] {
|
||||
nextNonce++
|
||||
}
|
||||
|
||||
case strict && m.Message.Nonce > nextNonce+MaxNonceGap:
|
||||
return false, xerrors.Errorf("message nonce has too big a gap from expected nonce (Nonce: %d, nextNonce: %d): %w", m.Message.Nonce, nextNonce, ErrNonceGap)
|
||||
|
||||
case m.Message.Nonce > nextNonce:
|
||||
nonceGap = true
|
||||
}
|
||||
|
||||
exms, has := ms.msgs[m.Message.Nonce]
|
||||
if has {
|
||||
// refuse RBF if we have a gap
|
||||
if strict && nonceGap {
|
||||
return false, xerrors.Errorf("rejecting replace by fee because of nonce gap (Nonce: %d, nextNonce: %d): %w", m.Message.Nonce, nextNonce, ErrNonceGap)
|
||||
}
|
||||
|
||||
if m.Cid() != exms.Cid() {
|
||||
// check if RBF passes
|
||||
minPrice := exms.Message.GasPremium
|
||||
@@ -143,22 +194,87 @@ func (ms *msgSet) add(m *types.SignedMessage, mp *MessagePool) (bool, error) {
|
||||
m.Message.From, m.Message.Nonce, minPrice, m.Message.GasPremium,
|
||||
ErrRBFTooLowPremium)
|
||||
}
|
||||
} else {
|
||||
return false, xerrors.Errorf("message from %s with nonce %d already in mpool: %w",
|
||||
m.Message.From, m.Message.Nonce, ErrSoftValidationFailure)
|
||||
}
|
||||
|
||||
ms.requiredFunds.Sub(ms.requiredFunds, exms.Message.RequiredFunds().Int)
|
||||
//ms.requiredFunds.Sub(ms.requiredFunds, exms.Message.Value.Int)
|
||||
}
|
||||
|
||||
if !has && strict && len(ms.msgs) > MaxActorPendingMessages {
|
||||
log.Errorf("too many pending messages from actor %s", m.Message.From)
|
||||
return false, ErrTooManyPendingMessages
|
||||
}
|
||||
|
||||
if strict && nonceGap {
|
||||
log.Warnf("adding nonce-gapped message from %s (nonce: %d, nextNonce: %d)",
|
||||
m.Message.From, m.Message.Nonce, nextNonce)
|
||||
}
|
||||
|
||||
ms.nextNonce = nextNonce
|
||||
ms.msgs[m.Message.Nonce] = m
|
||||
ms.requiredFunds.Add(ms.requiredFunds, m.Message.RequiredFunds().Int)
|
||||
//ms.requiredFunds.Add(ms.requiredFunds, m.Message.Value.Int)
|
||||
|
||||
return !has, nil
|
||||
}
|
||||
|
||||
func (ms *msgSet) rm(nonce uint64, applied bool) {
|
||||
m, has := ms.msgs[nonce]
|
||||
if !has {
|
||||
if applied && nonce >= ms.nextNonce {
|
||||
// we removed a message we did not know about because it was applied
|
||||
// we need to adjust the nonce and check if we filled a gap
|
||||
ms.nextNonce = nonce + 1
|
||||
for _, fillGap := ms.msgs[ms.nextNonce]; fillGap; _, fillGap = ms.msgs[ms.nextNonce] {
|
||||
ms.nextNonce++
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
ms.requiredFunds.Sub(ms.requiredFunds, m.Message.RequiredFunds().Int)
|
||||
//ms.requiredFunds.Sub(ms.requiredFunds, m.Message.Value.Int)
|
||||
delete(ms.msgs, nonce)
|
||||
|
||||
// adjust next nonce
|
||||
if applied {
|
||||
// we removed a (known) message because it was applied in a tipset
|
||||
// we can't possibly have filled a gap in this case
|
||||
if nonce >= ms.nextNonce {
|
||||
ms.nextNonce = nonce + 1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// we removed a message because it was pruned
|
||||
// we have to adjust the nonce if it creates a gap or rewinds state
|
||||
if nonce < ms.nextNonce {
|
||||
ms.nextNonce = nonce
|
||||
}
|
||||
}
|
||||
|
||||
func (ms *msgSet) getRequiredFunds(nonce uint64) types.BigInt {
|
||||
requiredFunds := new(stdbig.Int).Set(ms.requiredFunds)
|
||||
|
||||
m, has := ms.msgs[nonce]
|
||||
if has {
|
||||
requiredFunds.Sub(requiredFunds, m.Message.RequiredFunds().Int)
|
||||
//requiredFunds.Sub(requiredFunds, m.Message.Value.Int)
|
||||
}
|
||||
|
||||
return types.BigInt{Int: requiredFunds}
|
||||
}
|
||||
|
||||
func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName) (*MessagePool, error) {
|
||||
cache, _ := lru.New2Q(build.BlsSignatureCacheSize)
|
||||
verifcache, _ := lru.New2Q(build.VerifSigCacheSize)
|
||||
|
||||
cfg, err := loadConfig(ds)
|
||||
if err != nil {
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("error loading mpool config: %w", err)
|
||||
}
|
||||
return nil, xerrors.Errorf("error loading mpool config: %w", err)
|
||||
}
|
||||
|
||||
mp := &MessagePool{
|
||||
@@ -166,6 +282,7 @@ func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName) (*Messa
|
||||
addSema: make(chan struct{}, 1),
|
||||
closer: make(chan struct{}),
|
||||
repubTk: build.Clock.Ticker(RepublishInterval),
|
||||
repubTrigger: make(chan struct{}, 1),
|
||||
localAddrs: make(map[address.Address]struct{}),
|
||||
pending: make(map[address.Address]*msgSet),
|
||||
minGasPrice: types.NewInt(0),
|
||||
@@ -183,12 +300,7 @@ func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName) (*Messa
|
||||
// enable initial prunes
|
||||
mp.pruneCooldown <- struct{}{}
|
||||
|
||||
if err := mp.loadLocal(); err != nil {
|
||||
log.Errorf("loading local messages: %+v", err)
|
||||
}
|
||||
|
||||
go mp.runLoop()
|
||||
|
||||
// load the current tipset and subscribe to head changes _before_ loading local messages
|
||||
mp.curTs = api.SubscribeHeadChanges(func(rev, app []*types.TipSet) error {
|
||||
err := mp.HeadChange(rev, app)
|
||||
if err != nil {
|
||||
@@ -197,6 +309,12 @@ func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName) (*Messa
|
||||
return err
|
||||
})
|
||||
|
||||
if err := mp.loadLocal(); err != nil {
|
||||
log.Errorf("loading local messages: %+v", err)
|
||||
}
|
||||
|
||||
go mp.runLoop()
|
||||
|
||||
return mp, nil
|
||||
}
|
||||
|
||||
@@ -224,6 +342,10 @@ func (mp *MessagePool) runLoop() {
|
||||
if err := mp.republishPendingMessages(); err != nil {
|
||||
log.Errorf("error while republishing messages: %s", err)
|
||||
}
|
||||
case <-mp.repubTrigger:
|
||||
if err := mp.republishPendingMessages(); err != nil {
|
||||
log.Errorf("error while republishing messages: %s", err)
|
||||
}
|
||||
case <-mp.pruneTrigger:
|
||||
if err := mp.pruneExcessMessages(); err != nil {
|
||||
log.Errorf("failed to prune excess messages from mempool: %s", err)
|
||||
@@ -245,37 +367,74 @@ func (mp *MessagePool) addLocal(m *types.SignedMessage, msgb []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mp *MessagePool) verifyMsgBeforePush(m *types.SignedMessage, epoch abi.ChainEpoch) error {
|
||||
// verifyMsgBeforeAdd verifies that the message meets the minimum criteria for block inclusio
|
||||
// and whether the message has enough funds to be included in the next 20 blocks.
|
||||
// If the message is not valid for block inclusion, it returns an error.
|
||||
// For local messages, if the message can be included in the next 20 blocks, it returns true to
|
||||
// signal that it should be immediately published. If the message cannot be included in the next 20
|
||||
// blocks, it returns false so that the message doesn't immediately get published (and ignored by our
|
||||
// peers); instead it will be published through the republish loop, once the base fee has fallen
|
||||
// sufficiently.
|
||||
// For non local messages, if the message cannot be included in the next 20 blocks it returns
|
||||
// a (soft) validation error.
|
||||
func (mp *MessagePool) verifyMsgBeforeAdd(m *types.SignedMessage, curTs *types.TipSet, local bool) (bool, error) {
|
||||
epoch := curTs.Height()
|
||||
minGas := vm.PricelistByEpoch(epoch).OnChainMessage(m.ChainLength())
|
||||
|
||||
if err := m.VMMessage().ValidForBlockInclusion(minGas.Total()); err != nil {
|
||||
return xerrors.Errorf("message will not be included in a block: %w", err)
|
||||
return false, xerrors.Errorf("message will not be included in a block: %w", err)
|
||||
}
|
||||
return nil
|
||||
|
||||
// this checks if the GasFeeCap is suffisciently high for inclusion in the next 20 blocks
|
||||
// if the GasFeeCap is too low, we soft reject the message (Ignore in pubsub) and rely
|
||||
// on republish to push it through later, if the baseFee has fallen.
|
||||
// this is a defensive check that stops minimum baseFee spam attacks from overloading validation
|
||||
// queues.
|
||||
// Note that for local messages, we always add them so that they can be accepted and republished
|
||||
// automatically.
|
||||
publish := local
|
||||
if strictBaseFeeValidation && len(curTs.Blocks()) > 0 {
|
||||
baseFee := curTs.Blocks()[0].ParentBaseFee
|
||||
baseFeeLowerBound := types.BigDiv(baseFee, baseFeeLowerBoundFactor)
|
||||
if m.Message.GasFeeCap.LessThan(baseFeeLowerBound) {
|
||||
if local {
|
||||
log.Warnf("local message will not be immediately published because GasFeeCap doesn't meet the lower bound for inclusion in the next 20 blocks (GasFeeCap: %s, baseFeeLowerBound: %s)",
|
||||
m.Message.GasFeeCap, baseFeeLowerBound)
|
||||
publish = false
|
||||
} else {
|
||||
return false, xerrors.Errorf("GasFeeCap doesn't meet base fee lower bound for inclusion in the next 20 blocks (GasFeeCap: %s, baseFeeLowerBound: %s): %w",
|
||||
m.Message.GasFeeCap, baseFeeLowerBound, ErrSoftValidationFailure)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return publish, nil
|
||||
}
|
||||
|
||||
func (mp *MessagePool) Push(m *types.SignedMessage) (cid.Cid, error) {
|
||||
err := mp.checkMessage(m)
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
// serialize push access to reduce lock contention
|
||||
mp.addSema <- struct{}{}
|
||||
defer func() {
|
||||
<-mp.addSema
|
||||
}()
|
||||
|
||||
mp.curTsLk.Lock()
|
||||
epoch := mp.curTs.Height()
|
||||
mp.curTsLk.Unlock()
|
||||
if err := mp.verifyMsgBeforePush(m, epoch); err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
msgb, err := m.Serialize()
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
if err := mp.Add(m); err != nil {
|
||||
mp.curTsLk.Lock()
|
||||
publish, err := mp.addTs(m, mp.curTs, true)
|
||||
if err != nil {
|
||||
mp.curTsLk.Unlock()
|
||||
return cid.Undef, err
|
||||
}
|
||||
mp.curTsLk.Unlock()
|
||||
|
||||
mp.lk.Lock()
|
||||
if err := mp.addLocal(m, msgb); err != nil {
|
||||
@@ -284,15 +443,24 @@ func (mp *MessagePool) Push(m *types.SignedMessage) (cid.Cid, error) {
|
||||
}
|
||||
mp.lk.Unlock()
|
||||
|
||||
return m.Cid(), mp.api.PubSubPublish(build.MessagesTopic(mp.netName), msgb)
|
||||
if publish {
|
||||
err = mp.api.PubSubPublish(build.MessagesTopic(mp.netName), msgb)
|
||||
}
|
||||
|
||||
return m.Cid(), err
|
||||
}
|
||||
|
||||
func (mp *MessagePool) Add(m *types.SignedMessage) error {
|
||||
func (mp *MessagePool) checkMessage(m *types.SignedMessage) error {
|
||||
// big messages are bad, anti DOS
|
||||
if m.Size() > 32*1024 {
|
||||
return xerrors.Errorf("mpool message too large (%dB): %w", m.Size(), ErrMessageTooBig)
|
||||
}
|
||||
|
||||
// Perform syntactic validation, minGas=0 as we check the actual mingas before we add it
|
||||
if err := m.Message.ValidForBlockInclusion(0); err != nil {
|
||||
return xerrors.Errorf("message not valid for block inclusion: %w", err)
|
||||
}
|
||||
|
||||
if m.Message.To == address.Undef {
|
||||
return ErrInvalidToAddr
|
||||
}
|
||||
@@ -301,8 +469,21 @@ func (mp *MessagePool) Add(m *types.SignedMessage) error {
|
||||
return ErrMessageValueTooHigh
|
||||
}
|
||||
|
||||
if m.Message.GasFeeCap.LessThan(minimumBaseFee) {
|
||||
return ErrGasFeeCapTooLow
|
||||
}
|
||||
|
||||
if err := mp.VerifyMsgSig(m); err != nil {
|
||||
log.Warnf("mpooladd signature verification failed: %s", err)
|
||||
log.Warnf("signature verification failed: %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mp *MessagePool) Add(m *types.SignedMessage) error {
|
||||
err := mp.checkMessage(m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -314,7 +495,9 @@ func (mp *MessagePool) Add(m *types.SignedMessage) error {
|
||||
|
||||
mp.curTsLk.Lock()
|
||||
defer mp.curTsLk.Unlock()
|
||||
return mp.addTs(m, mp.curTs)
|
||||
|
||||
_, err = mp.addTs(m, mp.curTs, false)
|
||||
return err
|
||||
}
|
||||
|
||||
func sigCacheKey(m *types.SignedMessage) (string, error) {
|
||||
@@ -353,48 +536,107 @@ func (mp *MessagePool) VerifyMsgSig(m *types.SignedMessage) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mp *MessagePool) addTs(m *types.SignedMessage, curTs *types.TipSet) error {
|
||||
func (mp *MessagePool) checkBalance(m *types.SignedMessage, curTs *types.TipSet) error {
|
||||
balance, err := mp.getStateBalance(m.Message.From, curTs)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to check sender balance: %s: %w", err, ErrSoftValidationFailure)
|
||||
}
|
||||
|
||||
requiredFunds := m.Message.RequiredFunds()
|
||||
if balance.LessThan(requiredFunds) {
|
||||
return xerrors.Errorf("not enough funds (required: %s, balance: %s): %w", types.FIL(requiredFunds), types.FIL(balance), ErrNotEnoughFunds)
|
||||
}
|
||||
|
||||
// add Value for soft failure check
|
||||
//requiredFunds = types.BigAdd(requiredFunds, m.Message.Value)
|
||||
|
||||
mset, ok := mp.pending[m.Message.From]
|
||||
if ok {
|
||||
requiredFunds = types.BigAdd(requiredFunds, mset.getRequiredFunds(m.Message.Nonce))
|
||||
}
|
||||
|
||||
if balance.LessThan(requiredFunds) {
|
||||
// Note: we fail here for ErrSoftValidationFailure to signal a soft failure because we might
|
||||
// be out of sync.
|
||||
return xerrors.Errorf("not enough funds including pending messages (required: %s, balance: %s): %w", types.FIL(requiredFunds), types.FIL(balance), ErrSoftValidationFailure)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mp *MessagePool) addTs(m *types.SignedMessage, curTs *types.TipSet, local bool) (bool, error) {
|
||||
snonce, err := mp.getStateNonce(m.Message.From, curTs)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to look up actor state nonce: %s: %w", err, ErrBroadcastAnyway)
|
||||
return false, xerrors.Errorf("failed to look up actor state nonce: %s: %w", err, ErrSoftValidationFailure)
|
||||
}
|
||||
|
||||
if snonce > m.Message.Nonce {
|
||||
return false, xerrors.Errorf("minimum expected nonce is %d: %w", snonce, ErrNonceTooLow)
|
||||
}
|
||||
|
||||
mp.lk.Lock()
|
||||
defer mp.lk.Unlock()
|
||||
|
||||
publish, err := mp.verifyMsgBeforeAdd(m, curTs, local)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if err := mp.checkBalance(m, curTs); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return publish, mp.addLocked(m, true)
|
||||
}
|
||||
|
||||
func (mp *MessagePool) addLoaded(m *types.SignedMessage) error {
|
||||
err := mp.checkMessage(m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mp.curTsLk.Lock()
|
||||
defer mp.curTsLk.Unlock()
|
||||
|
||||
curTs := mp.curTs
|
||||
|
||||
snonce, err := mp.getStateNonce(m.Message.From, curTs)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to look up actor state nonce: %s: %w", err, ErrSoftValidationFailure)
|
||||
}
|
||||
|
||||
if snonce > m.Message.Nonce {
|
||||
return xerrors.Errorf("minimum expected nonce is %d: %w", snonce, ErrNonceTooLow)
|
||||
}
|
||||
|
||||
balance, err := mp.getStateBalance(m.Message.From, curTs)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to check sender balance: %s: %w", err, ErrBroadcastAnyway)
|
||||
}
|
||||
|
||||
if balance.LessThan(m.Message.RequiredFunds()) {
|
||||
return xerrors.Errorf("not enough funds (required: %s, balance: %s): %w", types.FIL(m.Message.RequiredFunds()), types.FIL(balance), ErrNotEnoughFunds)
|
||||
}
|
||||
|
||||
mp.lk.Lock()
|
||||
defer mp.lk.Unlock()
|
||||
|
||||
return mp.addLocked(m)
|
||||
_, err = mp.verifyMsgBeforeAdd(m, curTs, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := mp.checkBalance(m, curTs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return mp.addLocked(m, false)
|
||||
}
|
||||
|
||||
func (mp *MessagePool) addSkipChecks(m *types.SignedMessage) error {
|
||||
mp.lk.Lock()
|
||||
defer mp.lk.Unlock()
|
||||
|
||||
return mp.addLocked(m)
|
||||
return mp.addLocked(m, false)
|
||||
}
|
||||
|
||||
func (mp *MessagePool) addLocked(m *types.SignedMessage) error {
|
||||
func (mp *MessagePool) addLocked(m *types.SignedMessage, strict bool) error {
|
||||
log.Debugf("mpooladd: %s %d", m.Message.From, m.Message.Nonce)
|
||||
if m.Signature.Type == crypto.SigTypeBLS {
|
||||
mp.blsSigCache.Add(m.Cid(), m.Signature)
|
||||
}
|
||||
|
||||
if m.Message.GasLimit > build.BlockGasLimit {
|
||||
return xerrors.Errorf("given message has too high of a gas limit")
|
||||
}
|
||||
|
||||
if _, err := mp.api.PutMessage(m); err != nil {
|
||||
log.Warnf("mpooladd cs.PutMessage failed: %s", err)
|
||||
return err
|
||||
@@ -407,13 +649,18 @@ func (mp *MessagePool) addLocked(m *types.SignedMessage) error {
|
||||
|
||||
mset, ok := mp.pending[m.Message.From]
|
||||
if !ok {
|
||||
mset = newMsgSet()
|
||||
nonce, err := mp.getStateNonce(m.Message.From, mp.curTs)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get initial actor nonce: %w", err)
|
||||
}
|
||||
|
||||
mset = newMsgSet(nonce)
|
||||
mp.pending[m.Message.From] = mset
|
||||
}
|
||||
|
||||
incr, err := mset.add(m, mp)
|
||||
incr, err := mset.add(m, mp, strict)
|
||||
if err != nil {
|
||||
log.Info(err)
|
||||
log.Debug(err)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -466,42 +713,16 @@ func (mp *MessagePool) getNonceLocked(addr address.Address, curTs *types.TipSet)
|
||||
}
|
||||
|
||||
func (mp *MessagePool) getStateNonce(addr address.Address, curTs *types.TipSet) (uint64, error) {
|
||||
// TODO: this method probably should be cached
|
||||
|
||||
act, err := mp.api.StateGetActor(addr, curTs)
|
||||
act, err := mp.api.GetActorAfter(addr, curTs)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
baseNonce := act.Nonce
|
||||
|
||||
// TODO: the correct thing to do here is probably to set curTs to chain.head
|
||||
// but since we have an accurate view of the world until a head change occurs,
|
||||
// this should be fine
|
||||
if curTs == nil {
|
||||
return baseNonce, nil
|
||||
}
|
||||
|
||||
msgs, err := mp.api.MessagesForTipset(curTs)
|
||||
if err != nil {
|
||||
return 0, xerrors.Errorf("failed to check messages for tipset: %w", err)
|
||||
}
|
||||
|
||||
for _, m := range msgs {
|
||||
msg := m.VMMessage()
|
||||
if msg.From == addr {
|
||||
if msg.Nonce != baseNonce {
|
||||
return 0, xerrors.Errorf("tipset %s has bad nonce ordering (%d != %d)", curTs.Cids(), msg.Nonce, baseNonce)
|
||||
}
|
||||
baseNonce++
|
||||
}
|
||||
}
|
||||
|
||||
return baseNonce, nil
|
||||
return act.Nonce, nil
|
||||
}
|
||||
|
||||
func (mp *MessagePool) getStateBalance(addr address.Address, ts *types.TipSet) (types.BigInt, error) {
|
||||
act, err := mp.api.StateGetActor(addr, ts)
|
||||
act, err := mp.api.GetActorAfter(addr, ts)
|
||||
if err != nil {
|
||||
return types.EmptyInt, err
|
||||
}
|
||||
@@ -548,6 +769,16 @@ func (mp *MessagePool) PushWithNonce(ctx context.Context, addr address.Address,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = mp.checkMessage(msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msgb, err := msg.Serialize()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// reacquire the locks and check state for consistency
|
||||
mp.curTsLk.Lock()
|
||||
defer mp.curTsLk.Unlock()
|
||||
@@ -568,33 +799,37 @@ func (mp *MessagePool) PushWithNonce(ctx context.Context, addr address.Address,
|
||||
return nil, ErrTryAgain
|
||||
}
|
||||
|
||||
if err := mp.verifyMsgBeforePush(msg, mp.curTs.Height()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msgb, err := msg.Serialize()
|
||||
publish, err := mp.verifyMsgBeforeAdd(msg, curTs, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := mp.addLocked(msg); err != nil {
|
||||
if err := mp.checkBalance(msg, curTs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := mp.addLocked(msg, true); err != nil {
|
||||
return nil, xerrors.Errorf("add locked failed: %w", err)
|
||||
}
|
||||
if err := mp.addLocal(msg, msgb); err != nil {
|
||||
log.Errorf("addLocal failed: %+v", err)
|
||||
}
|
||||
|
||||
return msg, mp.api.PubSubPublish(build.MessagesTopic(mp.netName), msgb)
|
||||
if publish {
|
||||
err = mp.api.PubSubPublish(build.MessagesTopic(mp.netName), msgb)
|
||||
}
|
||||
|
||||
return msg, err
|
||||
}
|
||||
|
||||
func (mp *MessagePool) Remove(from address.Address, nonce uint64) {
|
||||
func (mp *MessagePool) Remove(from address.Address, nonce uint64, applied bool) {
|
||||
mp.lk.Lock()
|
||||
defer mp.lk.Unlock()
|
||||
|
||||
mp.remove(from, nonce)
|
||||
mp.remove(from, nonce, applied)
|
||||
}
|
||||
|
||||
func (mp *MessagePool) remove(from address.Address, nonce uint64) {
|
||||
func (mp *MessagePool) remove(from address.Address, nonce uint64, applied bool) {
|
||||
mset, ok := mp.pending[from]
|
||||
if !ok {
|
||||
return
|
||||
@@ -611,22 +846,10 @@ func (mp *MessagePool) remove(from address.Address, nonce uint64) {
|
||||
|
||||
// NB: This deletes any message with the given nonce. This makes sense
|
||||
// as two messages with the same sender cannot have the same nonce
|
||||
delete(mset.msgs, nonce)
|
||||
mset.rm(nonce, applied)
|
||||
|
||||
if len(mset.msgs) == 0 {
|
||||
delete(mp.pending, from)
|
||||
} else {
|
||||
var max uint64
|
||||
for nonce := range mset.msgs {
|
||||
if max < nonce {
|
||||
max = nonce
|
||||
}
|
||||
}
|
||||
if max < nonce {
|
||||
max = nonce // we could have not seen the removed message before
|
||||
}
|
||||
|
||||
mset.nextNonce = max + 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -637,6 +860,10 @@ func (mp *MessagePool) Pending() ([]*types.SignedMessage, *types.TipSet) {
|
||||
mp.lk.Lock()
|
||||
defer mp.lk.Unlock()
|
||||
|
||||
return mp.allPending()
|
||||
}
|
||||
|
||||
func (mp *MessagePool) allPending() ([]*types.SignedMessage, *types.TipSet) {
|
||||
out := make([]*types.SignedMessage, 0)
|
||||
for a := range mp.pending {
|
||||
out = append(out, mp.pendingFor(a)...)
|
||||
@@ -644,6 +871,7 @@ func (mp *MessagePool) Pending() ([]*types.SignedMessage, *types.TipSet) {
|
||||
|
||||
return out, mp.curTs
|
||||
}
|
||||
|
||||
func (mp *MessagePool) PendingFor(a address.Address) ([]*types.SignedMessage, *types.TipSet) {
|
||||
mp.curTsLk.Lock()
|
||||
defer mp.curTsLk.Unlock()
|
||||
@@ -676,6 +904,7 @@ func (mp *MessagePool) HeadChange(revert []*types.TipSet, apply []*types.TipSet)
|
||||
mp.curTsLk.Lock()
|
||||
defer mp.curTsLk.Unlock()
|
||||
|
||||
repubTrigger := false
|
||||
rmsgs := make(map[address.Address]map[uint64]*types.SignedMessage)
|
||||
add := func(m *types.SignedMessage) {
|
||||
s, ok := rmsgs[m.Message.From]
|
||||
@@ -688,7 +917,7 @@ func (mp *MessagePool) HeadChange(revert []*types.TipSet, apply []*types.TipSet)
|
||||
rm := func(from address.Address, nonce uint64) {
|
||||
s, ok := rmsgs[from]
|
||||
if !ok {
|
||||
mp.Remove(from, nonce)
|
||||
mp.Remove(from, nonce, true)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -697,43 +926,73 @@ func (mp *MessagePool) HeadChange(revert []*types.TipSet, apply []*types.TipSet)
|
||||
return
|
||||
}
|
||||
|
||||
mp.Remove(from, nonce)
|
||||
mp.Remove(from, nonce, true)
|
||||
}
|
||||
|
||||
maybeRepub := func(cid cid.Cid) {
|
||||
if !repubTrigger {
|
||||
mp.lk.Lock()
|
||||
_, republished := mp.republished[cid]
|
||||
mp.lk.Unlock()
|
||||
if republished {
|
||||
repubTrigger = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var merr error
|
||||
|
||||
for _, ts := range revert {
|
||||
pts, err := mp.api.LoadTipSet(ts.Parents())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msgs, err := mp.MessagesForBlocks(ts.Blocks())
|
||||
if err != nil {
|
||||
return err
|
||||
log.Errorf("error loading reverted tipset parent: %s", err)
|
||||
merr = multierror.Append(merr, err)
|
||||
continue
|
||||
}
|
||||
|
||||
mp.curTs = pts
|
||||
|
||||
msgs, err := mp.MessagesForBlocks(ts.Blocks())
|
||||
if err != nil {
|
||||
log.Errorf("error retrieving messages for reverted block: %s", err)
|
||||
merr = multierror.Append(merr, err)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, msg := range msgs {
|
||||
add(msg)
|
||||
}
|
||||
}
|
||||
|
||||
for _, ts := range apply {
|
||||
mp.curTs = ts
|
||||
|
||||
for _, b := range ts.Blocks() {
|
||||
bmsgs, smsgs, err := mp.api.MessagesForBlock(b)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get messages for apply block %s(height %d) (msgroot = %s): %w", b.Cid(), b.Height, b.Messages, err)
|
||||
xerr := xerrors.Errorf("failed to get messages for apply block %s(height %d) (msgroot = %s): %w", b.Cid(), b.Height, b.Messages, err)
|
||||
log.Errorf("error retrieving messages for block: %s", xerr)
|
||||
merr = multierror.Append(merr, xerr)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, msg := range smsgs {
|
||||
rm(msg.Message.From, msg.Message.Nonce)
|
||||
maybeRepub(msg.Cid())
|
||||
}
|
||||
|
||||
for _, msg := range bmsgs {
|
||||
rm(msg.From, msg.Nonce)
|
||||
maybeRepub(msg.Cid())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mp.curTs = ts
|
||||
if repubTrigger {
|
||||
select {
|
||||
case mp.repubTrigger <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
for _, s := range rmsgs {
|
||||
@@ -745,7 +1004,9 @@ func (mp *MessagePool) HeadChange(revert []*types.TipSet, apply []*types.TipSet)
|
||||
}
|
||||
|
||||
if len(revert) > 0 && futureDebug {
|
||||
msgs, ts := mp.Pending()
|
||||
mp.lk.Lock()
|
||||
msgs, ts := mp.allPending()
|
||||
mp.lk.Unlock()
|
||||
|
||||
buckets := map[address.Address]*statBucket{}
|
||||
|
||||
@@ -762,7 +1023,8 @@ func (mp *MessagePool) HeadChange(revert []*types.TipSet, apply []*types.TipSet)
|
||||
}
|
||||
|
||||
for a, bkt := range buckets {
|
||||
act, err := mp.api.StateGetActor(a, ts)
|
||||
// TODO that might not be correct with GatActorAfter but it is only debug code
|
||||
act, err := mp.api.GetActorAfter(a, ts)
|
||||
if err != nil {
|
||||
log.Debugf("%s, err: %s\n", a, err)
|
||||
continue
|
||||
@@ -809,7 +1071,72 @@ func (mp *MessagePool) HeadChange(revert []*types.TipSet, apply []*types.TipSet)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return merr
|
||||
}
|
||||
|
||||
func (mp *MessagePool) runHeadChange(from *types.TipSet, to *types.TipSet, rmsgs map[address.Address]map[uint64]*types.SignedMessage) error {
|
||||
add := func(m *types.SignedMessage) {
|
||||
s, ok := rmsgs[m.Message.From]
|
||||
if !ok {
|
||||
s = make(map[uint64]*types.SignedMessage)
|
||||
rmsgs[m.Message.From] = s
|
||||
}
|
||||
s[m.Message.Nonce] = m
|
||||
}
|
||||
rm := func(from address.Address, nonce uint64) {
|
||||
s, ok := rmsgs[from]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if _, ok := s[nonce]; ok {
|
||||
delete(s, nonce)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
revert, apply, err := store.ReorgOps(mp.api.LoadTipSet, from, to)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to compute reorg ops for mpool pending messages: %w", err)
|
||||
}
|
||||
|
||||
var merr error
|
||||
|
||||
for _, ts := range revert {
|
||||
msgs, err := mp.MessagesForBlocks(ts.Blocks())
|
||||
if err != nil {
|
||||
log.Errorf("error retrieving messages for reverted block: %s", err)
|
||||
merr = multierror.Append(merr, err)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, msg := range msgs {
|
||||
add(msg)
|
||||
}
|
||||
}
|
||||
|
||||
for _, ts := range apply {
|
||||
for _, b := range ts.Blocks() {
|
||||
bmsgs, smsgs, err := mp.api.MessagesForBlock(b)
|
||||
if err != nil {
|
||||
xerr := xerrors.Errorf("failed to get messages for apply block %s(height %d) (msgroot = %s): %w", b.Cid(), b.Height, b.Messages, err)
|
||||
log.Errorf("error retrieving messages for block: %s", xerr)
|
||||
merr = multierror.Append(merr, xerr)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, msg := range smsgs {
|
||||
rm(msg.Message.From, msg.Message.Nonce)
|
||||
}
|
||||
|
||||
for _, msg := range bmsgs {
|
||||
rm(msg.From, msg.Nonce)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return merr
|
||||
}
|
||||
|
||||
type statBucket struct {
|
||||
@@ -862,6 +1189,7 @@ func (mp *MessagePool) Updates(ctx context.Context) (<-chan api.MpoolUpdate, err
|
||||
|
||||
go func() {
|
||||
defer mp.changes.Unsub(sub, localUpdates)
|
||||
defer close(out)
|
||||
|
||||
for {
|
||||
select {
|
||||
@@ -870,9 +1198,13 @@ func (mp *MessagePool) Updates(ctx context.Context) (<-chan api.MpoolUpdate, err
|
||||
case out <- u.(api.MpoolUpdate):
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-mp.closer:
|
||||
return
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-mp.closer:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
@@ -896,7 +1228,7 @@ func (mp *MessagePool) loadLocal() error {
|
||||
return xerrors.Errorf("unmarshaling local message: %w", err)
|
||||
}
|
||||
|
||||
if err := mp.Add(&sm); err != nil {
|
||||
if err := mp.addLoaded(&sm); err != nil {
|
||||
if xerrors.Is(err, ErrNonceTooLow) {
|
||||
continue // todo: drop the message from local cache (if above certain confidence threshold)
|
||||
}
|
||||
@@ -909,3 +1241,40 @@ func (mp *MessagePool) loadLocal() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mp *MessagePool) Clear(local bool) {
|
||||
mp.lk.Lock()
|
||||
defer mp.lk.Unlock()
|
||||
|
||||
// remove everything if local is true, including removing local messages from
|
||||
// the datastore
|
||||
if local {
|
||||
for a := range mp.localAddrs {
|
||||
mset, ok := mp.pending[a]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, m := range mset.msgs {
|
||||
err := mp.localMsgs.Delete(datastore.NewKey(string(m.Cid().Bytes())))
|
||||
if err != nil {
|
||||
log.Warnf("error deleting local message: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mp.pending = make(map[address.Address]*msgSet)
|
||||
mp.republished = nil
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// remove everything except the local messages
|
||||
for a := range mp.pending {
|
||||
_, isLocal := mp.localAddrs[a]
|
||||
if isLocal {
|
||||
continue
|
||||
}
|
||||
delete(mp.pending, a)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,16 +3,18 @@ package messagepool
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"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/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-datastore"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
@@ -30,14 +32,28 @@ type testMpoolAPI struct {
|
||||
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) applyBlock(t *testing.T, b *types.BlockHeader) {
|
||||
@@ -68,12 +84,11 @@ func (tma *testMpoolAPI) setBalanceRaw(addr address.Address, v types.BigInt) {
|
||||
|
||||
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) {
|
||||
@@ -81,18 +96,47 @@ 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{
|
||||
Code: builtin.StorageMarketActorCodeID,
|
||||
Nonce: tma.statenonce[addr],
|
||||
Nonce: nonce,
|
||||
Balance: balance,
|
||||
}, nil
|
||||
}
|
||||
@@ -141,7 +185,7 @@ func (tma *testMpoolAPI) LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error)
|
||||
}
|
||||
|
||||
func (tma *testMpoolAPI) ChainComputeBaseFee(ctx context.Context, ts *types.TipSet) (types.BigInt, error) {
|
||||
return types.NewInt(100), nil
|
||||
return tma.baseFee, nil
|
||||
}
|
||||
|
||||
func assertNonce(t *testing.T, mp *MessagePool, addr address.Address, val uint64) {
|
||||
@@ -178,7 +222,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 {
|
||||
@@ -204,7 +248,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())
|
||||
@@ -219,8 +263,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 {
|
||||
@@ -254,6 +347,7 @@ 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")
|
||||
}
|
||||
@@ -261,6 +355,12 @@ func TestRevertMessages(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPruningSimple(t *testing.T) {
|
||||
oldMaxNonceGap := MaxNonceGap
|
||||
MaxNonceGap = 1000
|
||||
defer func() {
|
||||
MaxNonceGap = oldMaxNonceGap
|
||||
}()
|
||||
|
||||
tma := newTestMpoolAPI()
|
||||
|
||||
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
@@ -275,13 +375,14 @@ func TestPruningSimple(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a := mock.MkBlock(nil, 1, 1)
|
||||
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++ {
|
||||
@@ -308,3 +409,257 @@ func TestPruningSimple(t *testing.T) {
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ type Provider interface {
|
||||
SubscribeHeadChanges(func(rev, app []*types.TipSet) error) *types.TipSet
|
||||
PutMessage(m types.ChainMsg) (cid.Cid, error)
|
||||
PubSubPublish(string, []byte) error
|
||||
StateGetActor(address.Address, *types.TipSet) (*types.Actor, 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)
|
||||
@@ -43,12 +43,17 @@ func (mpp *mpoolProvider) PutMessage(m types.ChainMsg) (cid.Cid, error) {
|
||||
}
|
||||
|
||||
func (mpp *mpoolProvider) PubSubPublish(k string, v []byte) error {
|
||||
return mpp.ps.Publish(k, v)
|
||||
return mpp.ps.Publish(k, v) //nolint
|
||||
}
|
||||
|
||||
func (mpp *mpoolProvider) StateGetActor(addr address.Address, ts *types.TipSet) (*types.Actor, error) {
|
||||
func (mpp *mpoolProvider) GetActorAfter(addr address.Address, ts *types.TipSet) (*types.Actor, error) {
|
||||
var act types.Actor
|
||||
return &act, mpp.sm.WithParentState(ts, mpp.sm.WithActor(addr, stmgr.GetActor(&act)))
|
||||
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) {
|
||||
|
||||
@@ -98,7 +98,7 @@ 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)
|
||||
mp.remove(m.Message.From, m.Message.Nonce, false)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
+49
-16
@@ -3,6 +3,7 @@ package messagepool
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
@@ -10,10 +11,13 @@ import (
|
||||
"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
|
||||
@@ -24,8 +28,14 @@ func (mp *MessagePool) republishPendingMessages() error {
|
||||
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 {
|
||||
@@ -50,7 +60,11 @@ func (mp *MessagePool) republishPendingMessages() error {
|
||||
|
||||
var chains []*msgChain
|
||||
for actor, mset := range pending {
|
||||
next := mp.createMessageChains(actor, mset, baseFee, ts)
|
||||
// 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...)
|
||||
}
|
||||
|
||||
@@ -62,15 +76,10 @@ func (mp *MessagePool) republishPendingMessages() error {
|
||||
return chains[i].Before(chains[j])
|
||||
})
|
||||
|
||||
// we don't republish negative performing chains; this is an error that will be screamed
|
||||
// at the user
|
||||
if chains[0].gasPerf < 0 {
|
||||
return xerrors.Errorf("skipping republish: all message chains have negative gas performance; best gas performance: %f", chains[0].gasPerf)
|
||||
}
|
||||
|
||||
gasLimit := int64(build.BlockGasLimit)
|
||||
minGas := int64(gasguess.MinGas)
|
||||
var msgs []*types.SignedMessage
|
||||
loop:
|
||||
for i := 0; i < len(chains); {
|
||||
chain := chains[i]
|
||||
|
||||
@@ -84,12 +93,6 @@ func (mp *MessagePool) republishPendingMessages() error {
|
||||
break
|
||||
}
|
||||
|
||||
// we don't republish negative performing chains, as they won't be included in
|
||||
// a block anyway
|
||||
if chain.gasPerf < 0 {
|
||||
break
|
||||
}
|
||||
|
||||
// has the chain been invalidated?
|
||||
if !chain.valid {
|
||||
i++
|
||||
@@ -98,15 +101,25 @@ func (mp *MessagePool) republishPendingMessages() error {
|
||||
|
||||
// does it fit in a block?
|
||||
if chain.gasLimit <= gasLimit {
|
||||
gasLimit -= chain.gasLimit
|
||||
msgs = append(msgs, chain.msgs...)
|
||||
// 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, ts, false)
|
||||
chain.Trim(gasLimit, mp, baseFee, true)
|
||||
for j := i; j < len(chains)-1; j++ {
|
||||
if chains[j].Before(chains[j+1]) {
|
||||
break
|
||||
@@ -115,6 +128,7 @@ func (mp *MessagePool) republishPendingMessages() error {
|
||||
}
|
||||
}
|
||||
|
||||
count := 0
|
||||
log.Infof("republishing %d messages", len(msgs))
|
||||
for _, m := range msgs {
|
||||
mb, err := m.Serialize()
|
||||
@@ -126,7 +140,26 @@ func (mp *MessagePool) republishPendingMessages() error {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
package messagepool
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/lotus/chain/messagepool/gasguess"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/ipfs/go-datastore"
|
||||
)
|
||||
|
||||
func TestRepubMessages(t *testing.T) {
|
||||
oldRepublishBatchDelay := RepublishBatchDelay
|
||||
RepublishBatchDelay = time.Microsecond
|
||||
defer func() {
|
||||
RepublishBatchDelay = oldRepublishBatchDelay
|
||||
}()
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
gasLimit := gasguess.Costs[gasguess.CostKey{Code: builtin.StorageMarketActorCodeID, M: 2}]
|
||||
|
||||
tma.setBalance(a1, 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)
|
||||
}
|
||||
}
|
||||
|
||||
if tma.published != 10 {
|
||||
t.Fatalf("expected to have published 10 messages, but got %d instead", tma.published)
|
||||
}
|
||||
|
||||
mp.repubTrigger <- struct{}{}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
if tma.published != 20 {
|
||||
t.Fatalf("expected to have published 20 messages, but got %d instead", tma.published)
|
||||
}
|
||||
}
|
||||
+139
-103
@@ -3,22 +3,29 @@ package messagepool
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
tbig "github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/messagepool/gasguess"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
abig "github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"github.com/ipfs/go-cid"
|
||||
)
|
||||
|
||||
var bigBlockGasLimit = big.NewInt(build.BlockGasLimit)
|
||||
|
||||
// this is *temporary* mutilation until we have implemented uncapped miner penalties -- it will go
|
||||
// away in the next fork.
|
||||
func allowNegativeChains(epoch abi.ChainEpoch) bool {
|
||||
return epoch < build.UpgradeBreezeHeight+5
|
||||
}
|
||||
|
||||
const MaxBlocks = 15
|
||||
|
||||
type msgChain struct {
|
||||
@@ -101,9 +108,9 @@ func (mp *MessagePool) selectMessagesOptimal(curTs, ts *types.TipSet, tq float64
|
||||
return chains[i].Before(chains[j])
|
||||
})
|
||||
|
||||
if len(chains) != 0 && chains[0].gasPerf < 0 {
|
||||
if !allowNegativeChains(curTs.Height()) && len(chains) != 0 && chains[0].gasPerf < 0 {
|
||||
log.Warnw("all messages in mpool have non-positive gas performance", "bestGasPerf", chains[0].gasPerf)
|
||||
return nil, nil
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// 3. Parition chains into blocks (without trimming)
|
||||
@@ -154,7 +161,7 @@ func (mp *MessagePool) selectMessagesOptimal(curTs, ts *types.TipSet, tq float64
|
||||
last := len(chains)
|
||||
for i, chain := range chains {
|
||||
// did we run out of performing chains?
|
||||
if chain.gasPerf < 0 {
|
||||
if !allowNegativeChains(curTs.Height()) && chain.gasPerf < 0 {
|
||||
break
|
||||
}
|
||||
|
||||
@@ -177,16 +184,16 @@ func (mp *MessagePool) selectMessagesOptimal(curTs, ts *types.TipSet, tq float64
|
||||
for i := len(chainDeps) - 1; i >= 0; i-- {
|
||||
curChain := chainDeps[i]
|
||||
curChain.merged = true
|
||||
// adjust the next chain for the parent, which is being merged
|
||||
if next := curChain.next; next != nil && next.effPerf > 0 {
|
||||
next.effPerf += next.parentOffset
|
||||
}
|
||||
result = append(result, curChain.msgs...)
|
||||
}
|
||||
|
||||
chain.merged = true
|
||||
// adjust the effective pefromance for all subsequent chains
|
||||
if next := chain.next; next != nil && next.effPerf > 0 {
|
||||
next.effPerf += next.parentOffset
|
||||
for next = next.next; next != nil && next.effPerf > 0; next = next.next {
|
||||
next.setEffPerf()
|
||||
}
|
||||
}
|
||||
result = append(result, chain.msgs...)
|
||||
gasLimit -= chainGasLimit
|
||||
@@ -218,7 +225,7 @@ tailLoop:
|
||||
for gasLimit >= minGas && last < len(chains) {
|
||||
// trim if necessary
|
||||
if chains[last].gasLimit > gasLimit {
|
||||
chains[last].Trim(gasLimit, mp, baseFee, ts, false)
|
||||
chains[last].Trim(gasLimit, mp, baseFee, allowNegativeChains(curTs.Height()))
|
||||
}
|
||||
|
||||
// push down if it hasn't been invalidated
|
||||
@@ -244,7 +251,7 @@ tailLoop:
|
||||
}
|
||||
|
||||
// if gasPerf < 0 we have no more profitable chains
|
||||
if chain.gasPerf < 0 {
|
||||
if !allowNegativeChains(curTs.Height()) && chain.gasPerf < 0 {
|
||||
break tailLoop
|
||||
}
|
||||
|
||||
@@ -285,7 +292,7 @@ tailLoop:
|
||||
}
|
||||
|
||||
// dependencies fit, just trim it
|
||||
chain.Trim(gasLimit-depGasLimit, mp, baseFee, ts, false)
|
||||
chain.Trim(gasLimit-depGasLimit, mp, baseFee, allowNegativeChains(curTs.Height()))
|
||||
last += i
|
||||
continue tailLoop
|
||||
}
|
||||
@@ -298,6 +305,69 @@ tailLoop:
|
||||
log.Infow("pack tail chains done", "took", dt)
|
||||
}
|
||||
|
||||
// if we have gasLimit to spare, pick some random (non-negative) chains to fill the block
|
||||
// we pick randomly so that we minimize the probability of duplication among all miners
|
||||
startRandom := time.Now()
|
||||
if gasLimit >= minGas {
|
||||
shuffleChains(chains)
|
||||
|
||||
for _, chain := range chains {
|
||||
// have we filled the block
|
||||
if gasLimit < minGas {
|
||||
break
|
||||
}
|
||||
|
||||
// has it been merged or invalidated?
|
||||
if chain.merged || !chain.valid {
|
||||
continue
|
||||
}
|
||||
|
||||
// is it negative?
|
||||
if !allowNegativeChains(curTs.Height()) && chain.gasPerf < 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// compute the dependencies that must be merged and the gas limit including deps
|
||||
chainGasLimit := chain.gasLimit
|
||||
depGasLimit := int64(0)
|
||||
var chainDeps []*msgChain
|
||||
for curChain := chain.prev; curChain != nil && !curChain.merged; curChain = curChain.prev {
|
||||
chainDeps = append(chainDeps, curChain)
|
||||
chainGasLimit += curChain.gasLimit
|
||||
depGasLimit += curChain.gasLimit
|
||||
}
|
||||
|
||||
// do the deps fit? if the deps won't fit, invalidate the chain
|
||||
if depGasLimit > gasLimit {
|
||||
chain.Invalidate()
|
||||
continue
|
||||
}
|
||||
|
||||
// do they fit as is? if it doesn't, trim to make it fit if possible
|
||||
if chainGasLimit > gasLimit {
|
||||
chain.Trim(gasLimit-depGasLimit, mp, baseFee, allowNegativeChains(curTs.Height()))
|
||||
|
||||
if !chain.valid {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// include it together with all dependencies
|
||||
for i := len(chainDeps) - 1; i >= 0; i-- {
|
||||
curChain := chainDeps[i]
|
||||
curChain.merged = true
|
||||
result = append(result, curChain.msgs...)
|
||||
}
|
||||
|
||||
chain.merged = true
|
||||
result = append(result, chain.msgs...)
|
||||
gasLimit -= chainGasLimit
|
||||
}
|
||||
}
|
||||
if dt := time.Since(startRandom); dt > time.Millisecond {
|
||||
log.Infow("pack random tail chains done", "took", dt)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -350,9 +420,9 @@ func (mp *MessagePool) selectMessagesGreedy(curTs, ts *types.TipSet) ([]*types.S
|
||||
return chains[i].Before(chains[j])
|
||||
})
|
||||
|
||||
if len(chains) != 0 && chains[0].gasPerf < 0 {
|
||||
if !allowNegativeChains(curTs.Height()) && len(chains) != 0 && chains[0].gasPerf < 0 {
|
||||
log.Warnw("all messages in mpool have non-positive gas performance", "bestGasPerf", chains[0].gasPerf)
|
||||
return nil, nil
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// 3. Merge the head chains to produce the list of messages selected for inclusion, subject to
|
||||
@@ -361,7 +431,7 @@ func (mp *MessagePool) selectMessagesGreedy(curTs, ts *types.TipSet) ([]*types.S
|
||||
last := len(chains)
|
||||
for i, chain := range chains {
|
||||
// did we run out of performing chains?
|
||||
if chain.gasPerf < 0 {
|
||||
if !allowNegativeChains(curTs.Height()) && chain.gasPerf < 0 {
|
||||
break
|
||||
}
|
||||
|
||||
@@ -390,7 +460,7 @@ func (mp *MessagePool) selectMessagesGreedy(curTs, ts *types.TipSet) ([]*types.S
|
||||
tailLoop:
|
||||
for gasLimit >= minGas && last < len(chains) {
|
||||
// trim
|
||||
chains[last].Trim(gasLimit, mp, baseFee, ts, false)
|
||||
chains[last].Trim(gasLimit, mp, baseFee, allowNegativeChains(curTs.Height()))
|
||||
|
||||
// push down if it hasn't been invalidated
|
||||
if chains[last].valid {
|
||||
@@ -410,7 +480,7 @@ tailLoop:
|
||||
}
|
||||
|
||||
// if gasPerf < 0 we have no more profitable chains
|
||||
if chain.gasPerf < 0 {
|
||||
if !allowNegativeChains(curTs.Height()) && chain.gasPerf < 0 {
|
||||
break tailLoop
|
||||
}
|
||||
|
||||
@@ -463,15 +533,27 @@ func (mp *MessagePool) selectPriorityMessages(pending map[address.Address]map[ui
|
||||
}
|
||||
}
|
||||
|
||||
if len(chains) == 0 {
|
||||
return nil, gasLimit
|
||||
}
|
||||
|
||||
// 2. Sort the chains
|
||||
sort.Slice(chains, func(i, j int) bool {
|
||||
return chains[i].Before(chains[j])
|
||||
})
|
||||
|
||||
// 3. Merge chains until the block limit; we are willing to include negative performing chains
|
||||
// as these are messages from our own miners
|
||||
if !allowNegativeChains(ts.Height()) && len(chains) != 0 && chains[0].gasPerf < 0 {
|
||||
log.Warnw("all priority messages in mpool have negative gas performance", "bestGasPerf", chains[0].gasPerf)
|
||||
return nil, gasLimit
|
||||
}
|
||||
|
||||
// 3. Merge chains until the block limit, as long as they have non-negative gas performance
|
||||
last := len(chains)
|
||||
for i, chain := range chains {
|
||||
if !allowNegativeChains(ts.Height()) && chain.gasPerf < 0 {
|
||||
break
|
||||
}
|
||||
|
||||
if chain.gasLimit <= gasLimit {
|
||||
gasLimit -= chain.gasLimit
|
||||
result = append(result, chain.msgs...)
|
||||
@@ -485,8 +567,8 @@ func (mp *MessagePool) selectPriorityMessages(pending map[address.Address]map[ui
|
||||
|
||||
tailLoop:
|
||||
for gasLimit >= minGas && last < len(chains) {
|
||||
// trim, without discarding negative performing messages
|
||||
chains[last].Trim(gasLimit, mp, baseFee, ts, true)
|
||||
// trim, discarding negative performing messages
|
||||
chains[last].Trim(gasLimit, mp, baseFee, allowNegativeChains(ts.Height()))
|
||||
|
||||
// push down if it hasn't been invalidated
|
||||
if chains[last].valid {
|
||||
@@ -504,6 +586,12 @@ tailLoop:
|
||||
if !chain.valid {
|
||||
continue
|
||||
}
|
||||
|
||||
// if gasPerf < 0 we have no more profitable chains
|
||||
if !allowNegativeChains(ts.Height()) && chain.gasPerf < 0 {
|
||||
break tailLoop
|
||||
}
|
||||
|
||||
// does it fit in the bock?
|
||||
if chain.gasLimit <= gasLimit {
|
||||
gasLimit -= chain.gasLimit
|
||||
@@ -516,9 +604,9 @@ tailLoop:
|
||||
continue tailLoop
|
||||
}
|
||||
|
||||
// the merge loop ended after processing all the chains and we probably still have gas to spare
|
||||
// -- mark the end.
|
||||
last = len(chains)
|
||||
// the merge loop ended after processing all the chains and we probably still have gas to spare;
|
||||
// end the loop
|
||||
break
|
||||
}
|
||||
|
||||
return result, gasLimit
|
||||
@@ -528,7 +616,6 @@ func (mp *MessagePool) getPendingMessages(curTs, ts *types.TipSet) (map[address.
|
||||
start := time.Now()
|
||||
|
||||
result := make(map[address.Address]map[uint64]*types.SignedMessage)
|
||||
haveCids := make(map[cid.Cid]struct{})
|
||||
defer func() {
|
||||
if dt := time.Since(start); dt > time.Millisecond {
|
||||
log.Infow("get pending messages done", "took", dt)
|
||||
@@ -554,10 +641,6 @@ func (mp *MessagePool) getPendingMessages(curTs, ts *types.TipSet) (map[address.
|
||||
}
|
||||
result[a] = msetCopy
|
||||
|
||||
// mark the messages as seen
|
||||
for _, m := range mset.msgs {
|
||||
haveCids[m.Cid()] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -566,84 +649,25 @@ func (mp *MessagePool) getPendingMessages(curTs, ts *types.TipSet) (map[address.
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// nope, we need to sync the tipsets
|
||||
for {
|
||||
if curTs.Height() == ts.Height() {
|
||||
if curTs.Equals(ts) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// different blocks in tipsets -- we mark them as seen so that they are not included in
|
||||
// in the message set we return, but *neither me (vyzo) nor why understand why*
|
||||
// this code is also probably completely untested in production, so I am adding a big fat
|
||||
// warning to revisit this case and sanity check this decision.
|
||||
log.Warnf("mpool tipset has same height as target tipset but it's not equal; beware of dragons!")
|
||||
|
||||
have, err := mp.MessagesForBlocks(ts.Blocks())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("error retrieving messages for tipset: %w", err)
|
||||
}
|
||||
|
||||
for _, m := range have {
|
||||
haveCids[m.Cid()] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
msgs, err := mp.MessagesForBlocks(ts.Blocks())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("error retrieving messages for tipset: %w", err)
|
||||
}
|
||||
|
||||
for _, m := range msgs {
|
||||
if _, have := haveCids[m.Cid()]; have {
|
||||
continue
|
||||
}
|
||||
|
||||
haveCids[m.Cid()] = struct{}{}
|
||||
mset, ok := result[m.Message.From]
|
||||
if !ok {
|
||||
mset = make(map[uint64]*types.SignedMessage)
|
||||
result[m.Message.From] = mset
|
||||
}
|
||||
|
||||
other, dupNonce := mset[m.Message.Nonce]
|
||||
if dupNonce {
|
||||
// duplicate nonce, selfishly keep the message with the highest GasPrice
|
||||
// if the gas prices are the same, keep the one with the highest GasLimit
|
||||
switch m.Message.GasPremium.Int.Cmp(other.Message.GasPremium.Int) {
|
||||
case 0:
|
||||
if m.Message.GasLimit > other.Message.GasLimit {
|
||||
mset[m.Message.Nonce] = m
|
||||
}
|
||||
case 1:
|
||||
mset[m.Message.Nonce] = m
|
||||
}
|
||||
} else {
|
||||
mset[m.Message.Nonce] = m
|
||||
}
|
||||
}
|
||||
|
||||
if curTs.Height() >= ts.Height() {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
ts, err = mp.api.LoadTipSet(ts.Parents())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("error loading parent tipset: %w", err)
|
||||
}
|
||||
if err := mp.runHeadChange(curTs, ts, result); err != nil {
|
||||
return nil, xerrors.Errorf("failed to process difference between mpool head and given head: %w", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (mp *MessagePool) getGasReward(msg *types.SignedMessage, baseFee types.BigInt, ts *types.TipSet) *big.Int {
|
||||
func (*MessagePool) getGasReward(msg *types.SignedMessage, baseFee types.BigInt) *big.Int {
|
||||
maxPremium := types.BigSub(msg.Message.GasFeeCap, baseFee)
|
||||
if types.BigCmp(maxPremium, msg.Message.GasPremium) < 0 {
|
||||
|
||||
if types.BigCmp(maxPremium, msg.Message.GasPremium) > 0 {
|
||||
maxPremium = msg.Message.GasPremium
|
||||
}
|
||||
gasReward := abig.Mul(maxPremium, types.NewInt(uint64(msg.Message.GasLimit)))
|
||||
|
||||
gasReward := tbig.Mul(maxPremium, types.NewInt(uint64(msg.Message.GasLimit)))
|
||||
return gasReward.Int
|
||||
}
|
||||
|
||||
func (mp *MessagePool) getGasPerf(gasReward *big.Int, gasLimit int64) float64 {
|
||||
func (*MessagePool) getGasPerf(gasReward *big.Int, gasLimit int64) float64 {
|
||||
// gasPerf = gasReward * build.BlockGasLimit / gasLimit
|
||||
a := new(big.Rat).SetInt(new(big.Int).Mul(gasReward, bigBlockGasLimit))
|
||||
b := big.NewRat(1, gasLimit)
|
||||
@@ -671,7 +695,12 @@ func (mp *MessagePool) createMessageChains(actor address.Address, mset map[uint6
|
||||
// cannot exceed the block limit; drop all messages that exceed the limit
|
||||
// - the total gasReward cannot exceed the actor's balance; drop all messages that exceed
|
||||
// the balance
|
||||
a, _ := mp.api.StateGetActor(actor, ts)
|
||||
a, err := mp.api.GetActorAfter(actor, ts)
|
||||
if err != nil {
|
||||
log.Errorf("failed to load actor state, not building chain for %s: %w", actor, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
curNonce := a.Nonce
|
||||
balance := a.Balance.Int
|
||||
gasLimit := int64(0)
|
||||
@@ -716,7 +745,7 @@ func (mp *MessagePool) createMessageChains(actor address.Address, mset map[uint6
|
||||
balance = new(big.Int).Sub(balance, value)
|
||||
}
|
||||
|
||||
gasReward := mp.getGasReward(m, baseFee, ts)
|
||||
gasReward := mp.getGasReward(m, baseFee)
|
||||
rewards = append(rewards, gasReward)
|
||||
}
|
||||
|
||||
@@ -817,10 +846,10 @@ func (mc *msgChain) Before(other *msgChain) bool {
|
||||
(mc.gasPerf == other.gasPerf && mc.gasReward.Cmp(other.gasReward) > 0)
|
||||
}
|
||||
|
||||
func (mc *msgChain) Trim(gasLimit int64, mp *MessagePool, baseFee types.BigInt, ts *types.TipSet, priority bool) {
|
||||
func (mc *msgChain) Trim(gasLimit int64, mp *MessagePool, baseFee types.BigInt, allowNegative bool) {
|
||||
i := len(mc.msgs) - 1
|
||||
for i >= 0 && (mc.gasLimit > gasLimit || (!priority && mc.gasPerf < 0)) {
|
||||
gasReward := mp.getGasReward(mc.msgs[i], baseFee, ts)
|
||||
for i >= 0 && (mc.gasLimit > gasLimit || (!allowNegative && mc.gasPerf < 0)) {
|
||||
gasReward := mp.getGasReward(mc.msgs[i], baseFee)
|
||||
mc.gasReward = new(big.Int).Sub(mc.gasReward, gasReward)
|
||||
mc.gasLimit -= mc.msgs[i].Message.GasLimit
|
||||
if mc.gasLimit > 0 {
|
||||
@@ -887,3 +916,10 @@ func (mc *msgChain) BeforeEffective(other *msgChain) bool {
|
||||
(mc.effPerf == other.effPerf && mc.gasPerf > other.gasPerf) ||
|
||||
(mc.effPerf == other.effPerf && mc.gasPerf == other.gasPerf && mc.gasReward.Cmp(other.gasReward) > 0)
|
||||
}
|
||||
|
||||
func shuffleChains(lst []*msgChain) {
|
||||
for i := range lst {
|
||||
j := rand.Intn(i + 1)
|
||||
lst[i], lst[j] = lst[j], lst[i]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,19 +2,20 @@ package messagepool
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/messagepool/gasguess"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/types/mock"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-datastore"
|
||||
|
||||
@@ -23,6 +24,11 @@ import (
|
||||
logging "github.com/ipfs/go-log"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// bump this for the selection tests
|
||||
MaxActorPendingMessages = 1000000
|
||||
}
|
||||
|
||||
func makeTestMessage(w *wallet.Wallet, from, to address.Address, nonce uint64, gasLimit int64, gasPrice uint64) *types.SignedMessage {
|
||||
msg := &types.Message{
|
||||
From: from,
|
||||
@@ -79,7 +85,7 @@ func TestMessageChains(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
block := mock.MkBlock(nil, 1, 1)
|
||||
block := tma.nextBlock()
|
||||
ts := mock.TipSet(block)
|
||||
|
||||
gasLimit := gasguess.Costs[gasguess.CostKey{Code: builtin.StorageMarketActorCodeID, M: 2}]
|
||||
@@ -317,7 +323,7 @@ func TestMessageChainSkipping(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
block := mock.MkBlock(nil, 1, 1)
|
||||
block := tma.nextBlock()
|
||||
ts := mock.TipSet(block)
|
||||
|
||||
gasLimit := gasguess.Costs[gasguess.CostKey{Code: builtin.StorageMarketActorCodeID, M: 2}]
|
||||
@@ -364,6 +370,12 @@ func TestMessageChainSkipping(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBasicMessageSelection(t *testing.T) {
|
||||
oldMaxNonceGap := MaxNonceGap
|
||||
MaxNonceGap = 1000
|
||||
defer func() {
|
||||
MaxNonceGap = oldMaxNonceGap
|
||||
}()
|
||||
|
||||
mp, tma := makeTestMpool()
|
||||
|
||||
// the actors
|
||||
@@ -387,7 +399,7 @@ func TestBasicMessageSelection(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
block := mock.MkBlock(nil, 1, 1)
|
||||
block := tma.nextBlock()
|
||||
ts := mock.TipSet(block)
|
||||
tma.applyBlock(t, block)
|
||||
|
||||
@@ -440,12 +452,12 @@ func TestBasicMessageSelection(t *testing.T) {
|
||||
}
|
||||
|
||||
// now we make a block with all the messages and advance the chain
|
||||
block2 := mock.MkBlock(ts, 2, 2)
|
||||
block2 := tma.nextBlock()
|
||||
tma.setBlockMessages(block2, msgs...)
|
||||
tma.applyBlock(t, block2)
|
||||
|
||||
// we should have no pending messages in the mpool
|
||||
pend, ts2 := mp.Pending()
|
||||
pend, _ := mp.Pending()
|
||||
if len(pend) != 0 {
|
||||
t.Fatalf("expected no pending messages, but got %d", len(pend))
|
||||
}
|
||||
@@ -458,13 +470,13 @@ func TestBasicMessageSelection(t *testing.T) {
|
||||
m = makeTestMessage(w2, a2, a1, uint64(i), gasLimit, uint64(i+1))
|
||||
msgs = append(msgs, m)
|
||||
}
|
||||
block3 := mock.MkBlock(ts2, 3, 3)
|
||||
block3 := tma.nextBlock()
|
||||
tma.setBlockMessages(block3, msgs...)
|
||||
ts3 := mock.TipSet(block3)
|
||||
|
||||
// now create another set of messages and add them to the mpool
|
||||
for i := 20; i < 30; i++ {
|
||||
m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(2*i+1))
|
||||
m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(2*i+200))
|
||||
mustAdd(t, mp, m)
|
||||
m = makeTestMessage(w2, a2, a1, uint64(i), gasLimit, uint64(i+1))
|
||||
mustAdd(t, mp, m)
|
||||
@@ -480,12 +492,12 @@ func TestBasicMessageSelection(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(msgs) != 40 {
|
||||
t.Fatalf("expected 40 messages, got %d", len(msgs))
|
||||
if len(msgs) != 20 {
|
||||
t.Fatalf("expected 20 messages, got %d", len(msgs))
|
||||
}
|
||||
|
||||
nextNonce = 10
|
||||
for i := 0; i < 20; i++ {
|
||||
nextNonce = 20
|
||||
for i := 0; i < 10; i++ {
|
||||
if msgs[i].Message.From != a1 {
|
||||
t.Fatalf("expected message from actor a1")
|
||||
}
|
||||
@@ -495,8 +507,8 @@ func TestBasicMessageSelection(t *testing.T) {
|
||||
nextNonce++
|
||||
}
|
||||
|
||||
nextNonce = 10
|
||||
for i := 20; i < 40; i++ {
|
||||
nextNonce = 20
|
||||
for i := 10; i < 20; i++ {
|
||||
if msgs[i].Message.From != a2 {
|
||||
t.Fatalf("expected message from actor a2")
|
||||
}
|
||||
@@ -531,7 +543,7 @@ func TestMessageSelectionTrimming(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
block := mock.MkBlock(nil, 1, 1)
|
||||
block := tma.nextBlock()
|
||||
ts := mock.TipSet(block)
|
||||
tma.applyBlock(t, block)
|
||||
|
||||
@@ -594,7 +606,7 @@ func TestPriorityMessageSelection(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
block := mock.MkBlock(nil, 1, 1)
|
||||
block := tma.nextBlock()
|
||||
ts := mock.TipSet(block)
|
||||
tma.applyBlock(t, block)
|
||||
|
||||
@@ -649,6 +661,169 @@ func TestPriorityMessageSelection(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPriorityMessageSelection2(t *testing.T) {
|
||||
mp, tma := makeTestMpool()
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
block := tma.nextBlock()
|
||||
ts := mock.TipSet(block)
|
||||
tma.applyBlock(t, block)
|
||||
|
||||
gasLimit := gasguess.Costs[gasguess.CostKey{Code: builtin.StorageMarketActorCodeID, M: 2}]
|
||||
|
||||
tma.setBalance(a1, 1) // in FIL
|
||||
tma.setBalance(a2, 1) // in FIL
|
||||
|
||||
mp.cfg.PriorityAddrs = []address.Address{a1}
|
||||
|
||||
nMessages := int(2 * build.BlockGasLimit / gasLimit)
|
||||
for i := 0; i < nMessages; i++ {
|
||||
bias := (nMessages - i) / 3
|
||||
m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(1+i%3+bias))
|
||||
mustAdd(t, mp, m)
|
||||
m = makeTestMessage(w2, a2, a1, uint64(i), gasLimit, uint64(1+i%3+bias))
|
||||
mustAdd(t, mp, m)
|
||||
}
|
||||
|
||||
msgs, err := mp.SelectMessages(ts, 1.0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expectedMsgs := int(build.BlockGasLimit / gasLimit)
|
||||
if len(msgs) != expectedMsgs {
|
||||
t.Fatalf("expected %d messages but got %d", expectedMsgs, len(msgs))
|
||||
}
|
||||
|
||||
// all messages must be from a1
|
||||
nextNonce := uint64(0)
|
||||
for _, m := range msgs {
|
||||
if m.Message.From != a1 {
|
||||
t.Fatal("expected messages from a1 before messages from a2")
|
||||
}
|
||||
if m.Message.Nonce != nextNonce {
|
||||
t.Fatalf("expected nonce %d but got %d", nextNonce, m.Message.Nonce)
|
||||
}
|
||||
nextNonce++
|
||||
}
|
||||
}
|
||||
|
||||
func TestPriorityMessageSelection3(t *testing.T) {
|
||||
t.Skip("reenable after removing allow negative")
|
||||
|
||||
mp, tma := makeTestMpool()
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
block := tma.nextBlock()
|
||||
ts := mock.TipSet(block)
|
||||
tma.applyBlock(t, block)
|
||||
|
||||
gasLimit := gasguess.Costs[gasguess.CostKey{Code: builtin.StorageMarketActorCodeID, M: 2}]
|
||||
|
||||
tma.setBalance(a1, 1) // in FIL
|
||||
tma.setBalance(a2, 1) // in FIL
|
||||
|
||||
mp.cfg.PriorityAddrs = []address.Address{a1}
|
||||
|
||||
tma.baseFee = types.NewInt(1000)
|
||||
nMessages := 10
|
||||
for i := 0; i < nMessages; i++ {
|
||||
bias := (nMessages - i) / 3
|
||||
m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(1000+i%3+bias))
|
||||
mustAdd(t, mp, m)
|
||||
// messages from a2 have negative performance
|
||||
m = makeTestMessage(w2, a2, a1, uint64(i), gasLimit, 100)
|
||||
mustAdd(t, mp, m)
|
||||
}
|
||||
|
||||
// test greedy selection
|
||||
msgs, err := mp.SelectMessages(ts, 1.0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expectedMsgs := 10
|
||||
if len(msgs) != expectedMsgs {
|
||||
t.Fatalf("expected %d messages but got %d", expectedMsgs, len(msgs))
|
||||
}
|
||||
|
||||
// all messages must be from a1
|
||||
nextNonce := uint64(0)
|
||||
for _, m := range msgs {
|
||||
if m.Message.From != a1 {
|
||||
t.Fatal("expected messages from a1 before messages from a2")
|
||||
}
|
||||
if m.Message.Nonce != nextNonce {
|
||||
t.Fatalf("expected nonce %d but got %d", nextNonce, m.Message.Nonce)
|
||||
}
|
||||
nextNonce++
|
||||
}
|
||||
|
||||
// test optimal selection
|
||||
msgs, err = mp.SelectMessages(ts, 0.1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expectedMsgs = 10
|
||||
if len(msgs) != expectedMsgs {
|
||||
t.Fatalf("expected %d messages but got %d", expectedMsgs, len(msgs))
|
||||
}
|
||||
|
||||
// all messages must be from a1
|
||||
nextNonce = uint64(0)
|
||||
for _, m := range msgs {
|
||||
if m.Message.From != a1 {
|
||||
t.Fatal("expected messages from a1 before messages from a2")
|
||||
}
|
||||
if m.Message.Nonce != nextNonce {
|
||||
t.Fatalf("expected nonce %d but got %d", nextNonce, m.Message.Nonce)
|
||||
}
|
||||
nextNonce++
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestOptimalMessageSelection1(t *testing.T) {
|
||||
// this test uses just a single actor sending messages with a low tq
|
||||
// the chain depenent merging algorithm should pick messages from the actor
|
||||
@@ -676,7 +851,7 @@ func TestOptimalMessageSelection1(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
block := mock.MkBlock(nil, 1, 1)
|
||||
block := tma.nextBlock()
|
||||
ts := mock.TipSet(block)
|
||||
tma.applyBlock(t, block)
|
||||
|
||||
@@ -743,7 +918,7 @@ func TestOptimalMessageSelection2(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
block := mock.MkBlock(nil, 1, 1)
|
||||
block := tma.nextBlock()
|
||||
ts := mock.TipSet(block)
|
||||
tma.applyBlock(t, block)
|
||||
|
||||
@@ -771,16 +946,26 @@ func TestOptimalMessageSelection2(t *testing.T) {
|
||||
t.Fatalf("expected %d messages, but got %d", expectedMsgs, len(msgs))
|
||||
}
|
||||
|
||||
nextNonce := uint64(0)
|
||||
var nFrom1, nFrom2 int
|
||||
var nextNonce1, nextNonce2 uint64
|
||||
for _, m := range msgs {
|
||||
if m.Message.From != a2 {
|
||||
t.Fatal("expected message from a2")
|
||||
if m.Message.From == a1 {
|
||||
if m.Message.Nonce != nextNonce1 {
|
||||
t.Fatalf("expected nonce %d but got %d", nextNonce1, m.Message.Nonce)
|
||||
}
|
||||
nextNonce1++
|
||||
nFrom1++
|
||||
} else {
|
||||
if m.Message.Nonce != nextNonce2 {
|
||||
t.Fatalf("expected nonce %d but got %d", nextNonce2, m.Message.Nonce)
|
||||
}
|
||||
nextNonce2++
|
||||
nFrom2++
|
||||
}
|
||||
}
|
||||
|
||||
if m.Message.Nonce != nextNonce {
|
||||
t.Fatalf("expected nonce %d but got %d", nextNonce, m.Message.Nonce)
|
||||
}
|
||||
nextNonce++
|
||||
if nFrom1 > nFrom2 {
|
||||
t.Fatalf("expected more messages from a2 than a1; nFrom1=%d nFrom2=%d", nFrom1, nFrom2)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -811,7 +996,7 @@ func TestOptimalMessageSelection3(t *testing.T) {
|
||||
wallets = append(wallets, w)
|
||||
}
|
||||
|
||||
block := mock.MkBlock(nil, 1, 1)
|
||||
block := tma.nextBlock()
|
||||
ts := mock.TipSet(block)
|
||||
tma.applyBlock(t, block)
|
||||
|
||||
@@ -824,7 +1009,7 @@ func TestOptimalMessageSelection3(t *testing.T) {
|
||||
nMessages := int(build.BlockGasLimit/gasLimit) + 1
|
||||
for i := 0; i < nMessages; i++ {
|
||||
for j := 0; j < nActors; j++ {
|
||||
premium := 500000 + 20000*(nActors-j) + (nMessages+2-i)/(3*nActors) + i%3
|
||||
premium := 500000 + 10000*(nActors-j) + (nMessages+2-i)/(30*nActors) + i%3
|
||||
m := makeTestMessage(wallets[j], actors[j], actors[j%nActors], uint64(i), gasLimit, uint64(premium))
|
||||
mustAdd(t, mp, m)
|
||||
}
|
||||
@@ -864,12 +1049,11 @@ func TestOptimalMessageSelection3(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand) (float64, float64) {
|
||||
// in this test we use 100 actors and send 10 blocks of messages.
|
||||
// actors send with an exponentially decreasing premium.
|
||||
func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium func() uint64) (float64, float64, float64) {
|
||||
// in this test we use 300 actors and send 10 blocks of messages.
|
||||
// actors send with an randomly distributed premium dictated by the getPremium function.
|
||||
// a number of miners select with varying ticket quality and we compare the
|
||||
// capacity and rewards of greedy selection -vs- optimal selection
|
||||
|
||||
mp, tma := makeTestMpool()
|
||||
|
||||
nActors := 300
|
||||
@@ -892,7 +1076,7 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand) (float64, flo
|
||||
wallets = append(wallets, w)
|
||||
}
|
||||
|
||||
block := mock.MkBlock(nil, 1, 1)
|
||||
block := tma.nextBlock()
|
||||
ts := mock.TipSet(block)
|
||||
tma.applyBlock(t, block)
|
||||
|
||||
@@ -909,10 +1093,10 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand) (float64, flo
|
||||
for i := 0; i < nMessages; i++ {
|
||||
from := rng.Intn(nActors)
|
||||
to := rng.Intn(nActors)
|
||||
premium := 20000*math.Exp(-3.*rand.Float64()) + 5000
|
||||
nonce := nonces[from]
|
||||
nonces[from]++
|
||||
m := makeTestMessage(wallets[from], actors[from], actors[to], uint64(nonce), gasLimit, uint64(premium))
|
||||
premium := getPremium()
|
||||
m := makeTestMessage(wallets[from], actors[from], actors[to], nonce, gasLimit, premium)
|
||||
mustAdd(t, mp, m)
|
||||
}
|
||||
|
||||
@@ -924,8 +1108,11 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand) (float64, flo
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
capacityBoost := 0.0
|
||||
rewardBoost := 0.0
|
||||
totalGreedyCapacity := 0.0
|
||||
totalGreedyReward := 0.0
|
||||
totalOptimalCapacity := 0.0
|
||||
totalOptimalReward := 0.0
|
||||
totalBestTQReward := 0.0
|
||||
const runs = 1
|
||||
for i := 0; i < runs; i++ {
|
||||
// 2. optimal selection
|
||||
@@ -935,76 +1122,162 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand) (float64, flo
|
||||
for ; i < MaxBlocks && minersRand > 0; i++ {
|
||||
minersRand -= winerProba[i]
|
||||
}
|
||||
nMiners := i
|
||||
if nMiners == 0 {
|
||||
nMiners := i - 1
|
||||
if nMiners < 1 {
|
||||
nMiners = 1
|
||||
}
|
||||
|
||||
optMsgs := make(map[cid.Cid]*types.SignedMessage)
|
||||
bestTq := 0.0
|
||||
var bestMsgs []*types.SignedMessage
|
||||
for j := 0; j < nMiners; j++ {
|
||||
tq := rng.Float64()
|
||||
msgs, err := mp.SelectMessages(ts, tq)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if tq > bestTq {
|
||||
bestMsgs = msgs
|
||||
}
|
||||
|
||||
for _, m := range msgs {
|
||||
optMsgs[m.Cid()] = m
|
||||
}
|
||||
}
|
||||
|
||||
totalGreedyCapacity += float64(len(greedyMsgs))
|
||||
totalOptimalCapacity += float64(len(optMsgs))
|
||||
boost := float64(len(optMsgs)) / float64(len(greedyMsgs))
|
||||
capacityBoost += boost
|
||||
|
||||
t.Logf("nMiners: %d", nMiners)
|
||||
t.Logf("greedy capacity %d, optimal capacity %d (x %.1f )", len(greedyMsgs),
|
||||
len(optMsgs), boost)
|
||||
if len(greedyMsgs) > len(optMsgs) {
|
||||
t.Fatal("greedy capacity higher than optimal capacity; wtf")
|
||||
t.Errorf("greedy capacity higher than optimal capacity; wtf")
|
||||
}
|
||||
|
||||
greedyReward := big.NewInt(0)
|
||||
for _, m := range greedyMsgs {
|
||||
greedyReward.Add(greedyReward, mp.getGasReward(m, baseFee, ts))
|
||||
greedyReward.Add(greedyReward, mp.getGasReward(m, baseFee))
|
||||
}
|
||||
|
||||
optReward := big.NewInt(0)
|
||||
for _, m := range optMsgs {
|
||||
optReward.Add(optReward, mp.getGasReward(m, baseFee, ts))
|
||||
optReward.Add(optReward, mp.getGasReward(m, baseFee))
|
||||
}
|
||||
|
||||
bestTqReward := big.NewInt(0)
|
||||
for _, m := range bestMsgs {
|
||||
bestTqReward.Add(bestTqReward, mp.getGasReward(m, baseFee))
|
||||
}
|
||||
|
||||
totalBestTQReward += float64(bestTqReward.Uint64())
|
||||
|
||||
nMinersBig := big.NewInt(int64(nMiners))
|
||||
greedyAvgReward, _ := new(big.Rat).SetFrac(greedyReward, nMinersBig).Float64()
|
||||
totalGreedyReward += greedyAvgReward
|
||||
optimalAvgReward, _ := new(big.Rat).SetFrac(optReward, nMinersBig).Float64()
|
||||
totalOptimalReward += optimalAvgReward
|
||||
|
||||
boost = optimalAvgReward / greedyAvgReward
|
||||
rewardBoost += boost
|
||||
t.Logf("greedy reward: %.0f, optimal reward: %.0f (x %.1f )", greedyAvgReward,
|
||||
optimalAvgReward, boost)
|
||||
|
||||
}
|
||||
|
||||
capacityBoost /= runs
|
||||
rewardBoost /= runs
|
||||
capacityBoost := totalOptimalCapacity / totalGreedyCapacity
|
||||
rewardBoost := totalOptimalReward / totalGreedyReward
|
||||
t.Logf("Average capacity boost: %f", capacityBoost)
|
||||
t.Logf("Average reward boost: %f", rewardBoost)
|
||||
t.Logf("Average best tq reward: %f", totalBestTQReward/runs/1e12)
|
||||
|
||||
logging.SetLogLevel("messagepool", "info")
|
||||
|
||||
return capacityBoost, rewardBoost
|
||||
return capacityBoost, rewardBoost, totalBestTQReward / runs / 1e12
|
||||
}
|
||||
|
||||
func TestCompetitiveMessageSelection(t *testing.T) {
|
||||
var capacityBoost, rewardBoost float64
|
||||
func makeExpPremiumDistribution(rng *rand.Rand) func() uint64 {
|
||||
return func() uint64 {
|
||||
premium := 20000*math.Exp(-3.*rng.Float64()) + 5000
|
||||
return uint64(premium)
|
||||
}
|
||||
}
|
||||
|
||||
func makeZipfPremiumDistribution(rng *rand.Rand) func() uint64 {
|
||||
zipf := rand.NewZipf(rng, 1.001, 1, 40000)
|
||||
return func() uint64 {
|
||||
return zipf.Uint64() + 10000
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompetitiveMessageSelectionExp(t *testing.T) {
|
||||
var capacityBoost, rewardBoost, tqReward float64
|
||||
seeds := []int64{1947, 1976, 2020, 2100, 10000, 143324, 432432, 131, 32, 45}
|
||||
for _, seed := range seeds {
|
||||
t.Log("running competitve message selection with seed", seed)
|
||||
cb, rb := testCompetitiveMessageSelection(t, rand.New(rand.NewSource(seed)))
|
||||
t.Log("running competitive message selection with Exponential premium distribution and seed", seed)
|
||||
rng := rand.New(rand.NewSource(seed))
|
||||
cb, rb, tqR := testCompetitiveMessageSelection(t, rng, makeExpPremiumDistribution(rng))
|
||||
capacityBoost += cb
|
||||
rewardBoost += rb
|
||||
tqReward += tqR
|
||||
}
|
||||
|
||||
capacityBoost /= float64(len(seeds))
|
||||
rewardBoost /= float64(len(seeds))
|
||||
tqReward /= float64(len(seeds))
|
||||
t.Logf("Average capacity boost across all seeds: %f", capacityBoost)
|
||||
t.Logf("Average reward boost across all seeds: %f", rewardBoost)
|
||||
t.Logf("Average reward of best ticket across all seeds: %f", tqReward)
|
||||
}
|
||||
|
||||
func TestCompetitiveMessageSelectionZipf(t *testing.T) {
|
||||
var capacityBoost, rewardBoost, tqReward float64
|
||||
seeds := []int64{1947, 1976, 2020, 2100, 10000, 143324, 432432, 131, 32, 45}
|
||||
for _, seed := range seeds {
|
||||
t.Log("running competitive message selection with Zipf premium distribution and seed", seed)
|
||||
rng := rand.New(rand.NewSource(seed))
|
||||
cb, rb, tqR := testCompetitiveMessageSelection(t, rng, makeZipfPremiumDistribution(rng))
|
||||
capacityBoost += cb
|
||||
rewardBoost += rb
|
||||
tqReward += tqR
|
||||
}
|
||||
|
||||
tqReward /= float64(len(seeds))
|
||||
capacityBoost /= float64(len(seeds))
|
||||
rewardBoost /= float64(len(seeds))
|
||||
t.Logf("Average capacity boost across all seeds: %f", capacityBoost)
|
||||
t.Logf("Average reward boost across all seeds: %f", rewardBoost)
|
||||
t.Logf("Average reward of best ticket across all seeds: %f", tqReward)
|
||||
}
|
||||
|
||||
func TestGasReward(t *testing.T) {
|
||||
tests := []struct {
|
||||
Premium uint64
|
||||
FeeCap uint64
|
||||
BaseFee uint64
|
||||
GasReward int64
|
||||
}{
|
||||
{Premium: 100, FeeCap: 200, BaseFee: 100, GasReward: 100},
|
||||
{Premium: 100, FeeCap: 200, BaseFee: 210, GasReward: -10},
|
||||
{Premium: 200, FeeCap: 250, BaseFee: 210, GasReward: 40},
|
||||
{Premium: 200, FeeCap: 250, BaseFee: 2000, GasReward: -1750},
|
||||
}
|
||||
|
||||
mp := new(MessagePool)
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(fmt.Sprintf("%v", test), func(t *testing.T) {
|
||||
msg := &types.SignedMessage{
|
||||
Message: types.Message{
|
||||
GasLimit: 10,
|
||||
GasFeeCap: types.NewInt(test.FeeCap),
|
||||
GasPremium: types.NewInt(test.Premium),
|
||||
},
|
||||
}
|
||||
rew := mp.getGasReward(msg, types.NewInt(test.BaseFee))
|
||||
if rew.Cmp(big.NewInt(test.GasReward*10)) != 0 {
|
||||
t.Errorf("bad reward: expected %d, got %s", test.GasReward*10, rew)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"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"
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
@@ -44,7 +44,7 @@ func SendHeadNotifs(nickname string) func(mctx helpers.MetricsCtx, lc fx.Lifecyc
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
sub, err := ps.Subscribe(topic)
|
||||
sub, err := ps.Subscribe(topic) //nolint
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -116,6 +116,7 @@ func sendHeadNotifs(ctx context.Context, ps *pubsub.PubSub, topic string, chain
|
||||
return err
|
||||
}
|
||||
|
||||
//nolint
|
||||
if err := ps.Publish(topic, b); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -246,7 +246,7 @@ func (st *StateTree) DeleteActor(addr address.Address) error {
|
||||
}
|
||||
|
||||
func (st *StateTree) Flush(ctx context.Context) (cid.Cid, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "stateTree.Flush")
|
||||
ctx, span := trace.StartSpan(ctx, "stateTree.Flush") //nolint:staticcheck
|
||||
defer span.End()
|
||||
if len(st.snaps.layers) != 1 {
|
||||
return cid.Undef, xerrors.Errorf("tried to flush state tree with snapshots on the stack")
|
||||
@@ -268,7 +268,7 @@ func (st *StateTree) Flush(ctx context.Context) (cid.Cid, error) {
|
||||
}
|
||||
|
||||
func (st *StateTree) Snapshot(ctx context.Context) error {
|
||||
ctx, span := trace.StartSpan(ctx, "stateTree.SnapShot")
|
||||
ctx, span := trace.StartSpan(ctx, "stateTree.SnapShot") //nolint:staticcheck
|
||||
defer span.End()
|
||||
|
||||
st.snaps.addLayer()
|
||||
|
||||
+6
-4
@@ -5,8 +5,8 @@ import (
|
||||
"fmt"
|
||||
|
||||
"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/ipfs/go-cid"
|
||||
"go.opencensus.io/trace"
|
||||
"golang.org/x/xerrors"
|
||||
@@ -29,6 +29,7 @@ func (sm *StateManager) CallRaw(ctx context.Context, msg *types.Message, bstate
|
||||
Bstore: sm.cs.Blockstore(),
|
||||
Syscalls: sm.cs.VMSys(),
|
||||
CircSupplyCalc: sm.GetCirculatingSupply,
|
||||
NtwkVersion: sm.GetNtwkVersion,
|
||||
BaseFee: types.NewInt(0),
|
||||
}
|
||||
|
||||
@@ -95,7 +96,7 @@ func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.
|
||||
|
||||
state := ts.ParentState()
|
||||
|
||||
r := store.NewChainRand(sm.cs, ts.Cids(), ts.Height())
|
||||
r := store.NewChainRand(sm.cs, ts.Cids())
|
||||
|
||||
return sm.CallRaw(ctx, msg, state, r, ts.Height())
|
||||
}
|
||||
@@ -113,7 +114,7 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri
|
||||
return nil, xerrors.Errorf("computing tipset state: %w", err)
|
||||
}
|
||||
|
||||
r := store.NewChainRand(sm.cs, ts.Cids(), ts.Height())
|
||||
r := store.NewChainRand(sm.cs, ts.Cids())
|
||||
|
||||
if span.IsRecordingEvents() {
|
||||
span.AddAttributes(
|
||||
@@ -130,6 +131,7 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri
|
||||
Bstore: sm.cs.Blockstore(),
|
||||
Syscalls: sm.cs.VMSys(),
|
||||
CircSupplyCalc: sm.GetCirculatingSupply,
|
||||
NtwkVersion: sm.GetNtwkVersion,
|
||||
BaseFee: ts.Blocks()[0].ParentBaseFee,
|
||||
}
|
||||
vmi, err := vm.NewVM(vmopt)
|
||||
|
||||
+304
-4
@@ -3,16 +3,28 @@ package stmgr
|
||||
import (
|
||||
"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/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"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"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
var ForksAtHeight = map[abi.ChainEpoch]func(context.Context, *StateManager, types.StateTree) error{}
|
||||
var ForksAtHeight = map[abi.ChainEpoch]func(context.Context, *StateManager, types.StateTree, *types.TipSet) error{
|
||||
build.UpgradeBreezeHeight: UpgradeFaucetBurnRecovery,
|
||||
}
|
||||
|
||||
func (sm *StateManager) handleStateForks(ctx context.Context, st types.StateTree, height abi.ChainEpoch) (err error) {
|
||||
func (sm *StateManager) handleStateForks(ctx context.Context, st types.StateTree, height abi.ChainEpoch, ts *types.TipSet) (err error) {
|
||||
f, ok := ForksAtHeight[height]
|
||||
if ok {
|
||||
err := f(ctx, sm, st)
|
||||
err := f(ctx, sm, st, ts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -20,3 +32,291 @@ func (sm *StateManager) handleStateForks(ctx context.Context, st types.StateTree
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type forEachTree interface {
|
||||
ForEach(func(address.Address, *types.Actor) error) error
|
||||
}
|
||||
|
||||
func doTransfer(tree types.StateTree, from, to address.Address, amt abi.TokenAmount) error {
|
||||
fromAct, err := tree.GetActor(from)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get 'from' actor for transfer: %w", err)
|
||||
}
|
||||
|
||||
fromAct.Balance = types.BigSub(fromAct.Balance, amt)
|
||||
if fromAct.Balance.Sign() < 0 {
|
||||
return xerrors.Errorf("(sanity) deducted more funds from target account than it had (%s, %s)", from, types.FIL(amt))
|
||||
}
|
||||
|
||||
if err := tree.SetActor(from, fromAct); err != nil {
|
||||
return xerrors.Errorf("failed to persist from actor: %w", err)
|
||||
}
|
||||
|
||||
toAct, err := tree.GetActor(to)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get 'to' actor for transfer: %w", err)
|
||||
}
|
||||
|
||||
toAct.Balance = types.BigAdd(toAct.Balance, amt)
|
||||
|
||||
if err := tree.SetActor(to, toAct); err != nil {
|
||||
return xerrors.Errorf("failed to persist to actor: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, tree types.StateTree, ts *types.TipSet) error {
|
||||
// Some initial parameters
|
||||
FundsForMiners := types.FromFil(1_000_000)
|
||||
LookbackEpoch := abi.ChainEpoch(32000)
|
||||
AccountCap := types.FromFil(0)
|
||||
BaseMinerBalance := types.FromFil(20)
|
||||
DesiredReimbursementBalance := types.FromFil(5_000_000)
|
||||
|
||||
isSystemAccount := func(addr address.Address) (bool, error) {
|
||||
id, err := address.IDFromAddress(addr)
|
||||
if err != nil {
|
||||
return false, xerrors.Errorf("id address: %w", err)
|
||||
}
|
||||
|
||||
if id < 1000 {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
minerFundsAlloc := func(pow, tpow abi.StoragePower) abi.TokenAmount {
|
||||
return types.BigDiv(types.BigMul(pow, FundsForMiners), tpow)
|
||||
}
|
||||
|
||||
// Grab lookback state for account checks
|
||||
lbts, err := sm.ChainStore().GetTipsetByHeight(ctx, LookbackEpoch, ts, false)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get tipset at lookback height: %w", err)
|
||||
}
|
||||
|
||||
var lbtree *state.StateTree
|
||||
if err = sm.WithStateTree(lbts.ParentState(), func(state *state.StateTree) error {
|
||||
lbtree = state
|
||||
return nil
|
||||
}); err != nil {
|
||||
return xerrors.Errorf("loading state tree failed: %w", err)
|
||||
}
|
||||
|
||||
ReserveAddress, err := address.NewFromString("t090")
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to parse reserve address: %w", err)
|
||||
}
|
||||
|
||||
fetree, ok := tree.(forEachTree)
|
||||
if !ok {
|
||||
return xerrors.Errorf("fork transition state tree doesnt support ForEach (%T)", tree)
|
||||
}
|
||||
|
||||
type transfer struct {
|
||||
From address.Address
|
||||
To address.Address
|
||||
Amt abi.TokenAmount
|
||||
}
|
||||
|
||||
var transfers []transfer
|
||||
|
||||
// Take all excess funds away, put them into the reserve account
|
||||
err = fetree.ForEach(func(addr address.Address, act *types.Actor) error {
|
||||
switch act.Code {
|
||||
case builtin.AccountActorCodeID, builtin.MultisigActorCodeID, builtin.PaymentChannelActorCodeID:
|
||||
sysAcc, err := isSystemAccount(addr)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("checking system account: %w", err)
|
||||
}
|
||||
|
||||
if !sysAcc {
|
||||
transfers = append(transfers, transfer{
|
||||
From: addr,
|
||||
To: ReserveAddress,
|
||||
Amt: act.Balance,
|
||||
})
|
||||
}
|
||||
case builtin.StorageMinerActorCodeID:
|
||||
var st miner.State
|
||||
if err := sm.WithActorState(ctx, &st)(act); err != nil {
|
||||
return xerrors.Errorf("failed to load miner state: %w", err)
|
||||
}
|
||||
|
||||
var available abi.TokenAmount
|
||||
{
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
log.Warnf("Get available balance failed (%s, %s, %s): %s", addr, act.Head, act.Balance, err)
|
||||
}
|
||||
available = abi.NewTokenAmount(0)
|
||||
}()
|
||||
// this panics if the miner doesnt have enough funds to cover their locked pledge
|
||||
available = st.GetAvailableBalance(act.Balance)
|
||||
}
|
||||
|
||||
transfers = append(transfers, transfer{
|
||||
From: addr,
|
||||
To: ReserveAddress,
|
||||
Amt: available,
|
||||
})
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("foreach over state tree failed: %w", err)
|
||||
}
|
||||
|
||||
// Execute transfers from previous step
|
||||
for _, t := range transfers {
|
||||
if err := doTransfer(tree, t.From, t.To, t.Amt); err != nil {
|
||||
return xerrors.Errorf("transfer %s %s->%s failed: %w", t.Amt, t.From, t.To, err)
|
||||
}
|
||||
}
|
||||
|
||||
// pull up power table to give miners back some funds proportional to their power
|
||||
var ps power.State
|
||||
powAct, err := tree.GetActor(builtin.StoragePowerActorAddr)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to load power actor: %w", err)
|
||||
}
|
||||
|
||||
cst := cbor.NewCborStore(sm.ChainStore().Blockstore())
|
||||
if err := cst.Get(ctx, powAct.Head, &ps); err != nil {
|
||||
return xerrors.Errorf("failed to get power actor state: %w", err)
|
||||
}
|
||||
|
||||
totalPower := ps.TotalBytesCommitted
|
||||
|
||||
var transfersBack []transfer
|
||||
// Now, we return some funds to places where they are needed
|
||||
err = fetree.ForEach(func(addr address.Address, act *types.Actor) error {
|
||||
lbact, err := lbtree.GetActor(addr)
|
||||
if err != nil {
|
||||
if !xerrors.Is(err, types.ErrActorNotFound) {
|
||||
return xerrors.Errorf("failed to get actor in lookback state")
|
||||
}
|
||||
}
|
||||
|
||||
prevBalance := abi.NewTokenAmount(0)
|
||||
if lbact != nil {
|
||||
prevBalance = lbact.Balance
|
||||
}
|
||||
|
||||
switch act.Code {
|
||||
case builtin.AccountActorCodeID, builtin.MultisigActorCodeID, builtin.PaymentChannelActorCodeID:
|
||||
nbalance := big.Min(prevBalance, AccountCap)
|
||||
if nbalance.Sign() != 0 {
|
||||
transfersBack = append(transfersBack, transfer{
|
||||
From: ReserveAddress,
|
||||
To: addr,
|
||||
Amt: nbalance,
|
||||
})
|
||||
}
|
||||
case builtin.StorageMinerActorCodeID:
|
||||
var st miner.State
|
||||
if err := sm.WithActorState(ctx, &st)(act); err != nil {
|
||||
return xerrors.Errorf("failed to load miner state: %w", err)
|
||||
}
|
||||
|
||||
var minfo miner.MinerInfo
|
||||
if err := cst.Get(ctx, st.Info, &minfo); err != nil {
|
||||
return xerrors.Errorf("failed to get miner info: %w", err)
|
||||
}
|
||||
|
||||
sectorsArr, err := adt.AsArray(sm.ChainStore().Store(ctx), st.Sectors)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to load sectors array: %w", err)
|
||||
}
|
||||
|
||||
slen := sectorsArr.Length()
|
||||
|
||||
power := types.BigMul(types.NewInt(slen), types.NewInt(uint64(minfo.SectorSize)))
|
||||
|
||||
mfunds := minerFundsAlloc(power, totalPower)
|
||||
transfersBack = append(transfersBack, transfer{
|
||||
From: ReserveAddress,
|
||||
To: minfo.Worker,
|
||||
Amt: mfunds,
|
||||
})
|
||||
|
||||
// Now make sure to give each miner who had power at the lookback some FIL
|
||||
lbact, err := lbtree.GetActor(addr)
|
||||
if err == nil {
|
||||
var lbst miner.State
|
||||
if err := sm.WithActorState(ctx, &lbst)(lbact); err != nil {
|
||||
return xerrors.Errorf("failed to load miner state: %w", err)
|
||||
}
|
||||
|
||||
lbsectors, err := adt.AsArray(sm.ChainStore().Store(ctx), lbst.Sectors)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to load lb sectors array: %w", err)
|
||||
}
|
||||
|
||||
if lbsectors.Length() > 0 {
|
||||
transfersBack = append(transfersBack, transfer{
|
||||
From: ReserveAddress,
|
||||
To: minfo.Worker,
|
||||
Amt: BaseMinerBalance,
|
||||
})
|
||||
}
|
||||
|
||||
} else {
|
||||
log.Warnf("failed to get miner in lookback state: %s", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("foreach over state tree failed: %w", err)
|
||||
}
|
||||
|
||||
for _, t := range transfersBack {
|
||||
if err := doTransfer(tree, t.From, t.To, t.Amt); err != nil {
|
||||
return xerrors.Errorf("transfer %s %s->%s failed: %w", t.Amt, t.From, t.To, err)
|
||||
}
|
||||
}
|
||||
|
||||
// transfer all burnt funds back to the reserve account
|
||||
burntAct, err := tree.GetActor(builtin.BurntFundsActorAddr)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to load burnt funds actor: %w", err)
|
||||
}
|
||||
if err := doTransfer(tree, builtin.BurntFundsActorAddr, ReserveAddress, burntAct.Balance); err != nil {
|
||||
return xerrors.Errorf("failed to unburn funds: %w", err)
|
||||
}
|
||||
|
||||
// Top up the reimbursement service
|
||||
reimbAddr, err := address.NewFromString("t0111")
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to parse reimbursement service address")
|
||||
}
|
||||
|
||||
reimb, err := tree.GetActor(reimbAddr)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to load reimbursement account actor: %w", err)
|
||||
}
|
||||
|
||||
difference := types.BigSub(DesiredReimbursementBalance, reimb.Balance)
|
||||
if err := doTransfer(tree, ReserveAddress, reimbAddr, difference); err != nil {
|
||||
return xerrors.Errorf("failed to top up reimbursement account: %w", err)
|
||||
}
|
||||
|
||||
// Now, a final sanity check to make sure the balances all check out
|
||||
total := abi.NewTokenAmount(0)
|
||||
err = fetree.ForEach(func(addr address.Address, act *types.Actor) error {
|
||||
total = types.BigAdd(total, act.Balance)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("checking final state balance failed: %w", err)
|
||||
}
|
||||
|
||||
exp := types.FromFil(build.FilBase)
|
||||
if !exp.Equals(total) {
|
||||
return xerrors.Errorf("resultant state tree account balance was not correct: %s", total)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"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"
|
||||
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
@@ -119,7 +119,7 @@ func TestForkHeightTriggers(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
stmgr.ForksAtHeight[testForkHeight] = func(ctx context.Context, sm *StateManager, st types.StateTree) error {
|
||||
stmgr.ForksAtHeight[testForkHeight] = func(ctx context.Context, sm *StateManager, st types.StateTree, ts *types.TipSet) error {
|
||||
cst := cbor.NewCborStore(sm.ChainStore().Blockstore())
|
||||
|
||||
act, err := st.GetActor(taddr)
|
||||
|
||||
+137
-26
@@ -3,9 +3,12 @@ package stmgr
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
"sync"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
@@ -17,8 +20,8 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
|
||||
"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/market"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/reward"
|
||||
@@ -144,7 +147,7 @@ func (sm *StateManager) ExecutionTrace(ctx context.Context, ts *types.TipSet) (c
|
||||
|
||||
type ExecCallback func(cid.Cid, *types.Message, *vm.ApplyRet) error
|
||||
|
||||
func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEpoch, pstate cid.Cid, bms []store.BlockMessages, epoch abi.ChainEpoch, r vm.Rand, cb ExecCallback, baseFee abi.TokenAmount) (cid.Cid, cid.Cid, error) {
|
||||
func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEpoch, pstate cid.Cid, bms []store.BlockMessages, epoch abi.ChainEpoch, r vm.Rand, cb ExecCallback, baseFee abi.TokenAmount, ts *types.TipSet) (cid.Cid, cid.Cid, error) {
|
||||
|
||||
vmopt := &vm.VMOpts{
|
||||
StateBase: pstate,
|
||||
@@ -153,6 +156,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
|
||||
Bstore: sm.cs.Blockstore(),
|
||||
Syscalls: sm.cs.VMSys(),
|
||||
CircSupplyCalc: sm.GetCirculatingSupply,
|
||||
NtwkVersion: sm.GetNtwkVersion,
|
||||
BaseFee: baseFee,
|
||||
}
|
||||
|
||||
@@ -197,7 +201,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
|
||||
|
||||
for i := parentEpoch; i < epoch; i++ {
|
||||
// handle state forks
|
||||
err = sm.handleStateForks(ctx, vmi.StateTree(), i)
|
||||
err = sm.handleStateForks(ctx, vmi.StateTree(), i, ts)
|
||||
if err != nil {
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("error handling state forks: %w", err)
|
||||
}
|
||||
@@ -323,7 +327,7 @@ func (sm *StateManager) computeTipSetState(ctx context.Context, ts *types.TipSet
|
||||
|
||||
var parentEpoch abi.ChainEpoch
|
||||
pstate := blks[0].ParentStateRoot
|
||||
if len(blks[0].Parents) > 0 {
|
||||
if blks[0].Height > 0 {
|
||||
parent, err := sm.cs.GetBlock(blks[0].Parents[0])
|
||||
if err != nil {
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("getting parent block: %w", err)
|
||||
@@ -337,7 +341,7 @@ func (sm *StateManager) computeTipSetState(ctx context.Context, ts *types.TipSet
|
||||
cids[i] = v.Cid()
|
||||
}
|
||||
|
||||
r := store.NewChainRand(sm.cs, cids, blks[0].Height)
|
||||
r := store.NewChainRand(sm.cs, cids)
|
||||
|
||||
blkmsgs, err := sm.cs.BlockMsgsForTipset(ts)
|
||||
if err != nil {
|
||||
@@ -346,7 +350,7 @@ func (sm *StateManager) computeTipSetState(ctx context.Context, ts *types.TipSet
|
||||
|
||||
baseFee := blks[0].ParentBaseFee
|
||||
|
||||
return sm.ApplyBlocks(ctx, parentEpoch, pstate, blkmsgs, blks[0].Height, r, cb, baseFee)
|
||||
return sm.ApplyBlocks(ctx, parentEpoch, pstate, blkmsgs, blks[0].Height, r, cb, baseFee, ts)
|
||||
}
|
||||
|
||||
func (sm *StateManager) parentState(ts *types.TipSet) cid.Cid {
|
||||
@@ -787,7 +791,7 @@ type genesisActor struct {
|
||||
initBal abi.TokenAmount
|
||||
}
|
||||
|
||||
// sets up information about the non-multisig actors in the genesis state
|
||||
// sets up information about the actors in the genesis state
|
||||
func (sm *StateManager) setupGenesisActors(ctx context.Context) error {
|
||||
|
||||
gi := genesisInfo{}
|
||||
@@ -850,21 +854,24 @@ func (sm *StateManager) setupGenesisActors(ctx context.Context) error {
|
||||
}
|
||||
|
||||
} else if act.Code == builtin.AccountActorCodeID {
|
||||
// should exclude burnt funds actor and "remainder account actor"
|
||||
// should only ever be "faucet" accounts in testnets
|
||||
kaddr, err := address.NewFromBytes([]byte(k))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("decoding address: %w", err)
|
||||
}
|
||||
|
||||
kid, err := sTree.LookupID(kaddr)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("resolving address: %w", err)
|
||||
}
|
||||
if kaddr != builtin.BurntFundsActorAddr {
|
||||
kid, err := sTree.LookupID(kaddr)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("resolving address: %w", err)
|
||||
}
|
||||
|
||||
gi.genesisActors = append(gi.genesisActors, genesisActor{
|
||||
addr: kid,
|
||||
initBal: act.Balance,
|
||||
})
|
||||
gi.genesisActors = append(gi.genesisActors, genesisActor{
|
||||
addr: kid,
|
||||
initBal: act.Balance,
|
||||
})
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@@ -888,6 +895,83 @@ func (sm *StateManager) setupGenesisActors(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// sets up information about the actors in the genesis state
|
||||
// For testnet we use a hardcoded set of multisig states, instead of what's actually in the genesis multisigs
|
||||
// We also do not consider ANY account actors (including the faucet)
|
||||
func (sm *StateManager) setupGenesisActorsTestnet(ctx context.Context) error {
|
||||
|
||||
gi := genesisInfo{}
|
||||
|
||||
gb, err := sm.cs.GetGenesis()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting genesis block: %w", err)
|
||||
}
|
||||
|
||||
gts, err := types.NewTipSet([]*types.BlockHeader{gb})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting genesis tipset: %w", err)
|
||||
}
|
||||
|
||||
st, _, err := sm.TipSetState(ctx, gts)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting genesis tipset state: %w", err)
|
||||
}
|
||||
|
||||
cst := cbor.NewCborStore(sm.cs.Blockstore())
|
||||
sTree, err := state.LoadStateTree(cst, st)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("loading state tree: %w", err)
|
||||
}
|
||||
|
||||
gi.genesisMarketFunds, err = getFilMarketLocked(ctx, sTree)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("setting up genesis market funds: %w", err)
|
||||
}
|
||||
|
||||
gi.genesisPledge, err = getFilPowerLocked(ctx, sTree)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("setting up genesis pledge: %w", err)
|
||||
}
|
||||
|
||||
totalsByEpoch := make(map[abi.ChainEpoch]abi.TokenAmount)
|
||||
|
||||
// 6 months
|
||||
sixMonths := abi.ChainEpoch(183 * builtin.EpochsInDay)
|
||||
totalsByEpoch[sixMonths] = big.NewInt(49_929_341)
|
||||
totalsByEpoch[sixMonths] = big.Add(totalsByEpoch[sixMonths], big.NewInt(32_787_700))
|
||||
|
||||
// 1 year
|
||||
oneYear := abi.ChainEpoch(365 * builtin.EpochsInDay)
|
||||
totalsByEpoch[oneYear] = big.NewInt(22_421_712)
|
||||
|
||||
// 2 years
|
||||
twoYears := abi.ChainEpoch(2 * 365 * builtin.EpochsInDay)
|
||||
totalsByEpoch[twoYears] = big.NewInt(7_223_364)
|
||||
|
||||
// 3 years
|
||||
threeYears := abi.ChainEpoch(3 * 365 * builtin.EpochsInDay)
|
||||
totalsByEpoch[threeYears] = big.NewInt(87_637_883)
|
||||
|
||||
// 6 years
|
||||
sixYears := abi.ChainEpoch(6 * 365 * builtin.EpochsInDay)
|
||||
totalsByEpoch[sixYears] = big.NewInt(100_000_000)
|
||||
totalsByEpoch[sixYears] = big.Add(totalsByEpoch[sixYears], big.NewInt(300_000_000))
|
||||
|
||||
gi.genesisMsigs = make([]multisig.State, 0, len(totalsByEpoch))
|
||||
for k, v := range totalsByEpoch {
|
||||
ns := multisig.State{
|
||||
InitialBalance: v,
|
||||
UnlockDuration: k,
|
||||
PendingTxns: cid.Undef,
|
||||
}
|
||||
gi.genesisMsigs = append(gi.genesisMsigs, ns)
|
||||
}
|
||||
|
||||
sm.genInfo = &gi
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetVestedFunds returns all funds that have "left" actors that are in the genesis state:
|
||||
// - For Multisigs, it counts the actual amounts that have vested at the given epoch
|
||||
// - For Accounts, it counts max(currentBalance - genesisBalance, 0).
|
||||
@@ -898,7 +982,7 @@ func (sm *StateManager) GetFilVested(ctx context.Context, height abi.ChainEpoch,
|
||||
vf = big.Add(vf, au)
|
||||
}
|
||||
|
||||
// these should only ever be "faucet" accounts in testnets
|
||||
// there should not be any such accounts in testnet (and also none in mainnet?)
|
||||
for _, v := range sm.genInfo.genesisActors {
|
||||
act, err := st.GetActor(v.addr)
|
||||
if err != nil {
|
||||
@@ -984,34 +1068,34 @@ func GetFilBurnt(ctx context.Context, st *state.StateTree) (abi.TokenAmount, err
|
||||
return burnt.Balance, nil
|
||||
}
|
||||
|
||||
func (sm *StateManager) GetCirculatingSupply(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (abi.TokenAmount, error) {
|
||||
func (sm *StateManager) GetCirculatingSupplyDetailed(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (api.CirculatingSupply, error) {
|
||||
sm.genesisMsigLk.Lock()
|
||||
defer sm.genesisMsigLk.Unlock()
|
||||
if sm.genInfo == nil {
|
||||
err := sm.setupGenesisActors(ctx)
|
||||
err := sm.setupGenesisActorsTestnet(ctx)
|
||||
if err != nil {
|
||||
return big.Zero(), xerrors.Errorf("failed to setup genesis information: %w", err)
|
||||
return api.CirculatingSupply{}, xerrors.Errorf("failed to setup genesis information: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
filVested, err := sm.GetFilVested(ctx, height, st)
|
||||
if err != nil {
|
||||
return big.Zero(), xerrors.Errorf("failed to calculate filVested: %w", err)
|
||||
return api.CirculatingSupply{}, xerrors.Errorf("failed to calculate filVested: %w", err)
|
||||
}
|
||||
|
||||
filMined, err := GetFilMined(ctx, st)
|
||||
if err != nil {
|
||||
return big.Zero(), xerrors.Errorf("failed to calculate filMined: %w", err)
|
||||
return api.CirculatingSupply{}, xerrors.Errorf("failed to calculate filMined: %w", err)
|
||||
}
|
||||
|
||||
filBurnt, err := GetFilBurnt(ctx, st)
|
||||
if err != nil {
|
||||
return big.Zero(), xerrors.Errorf("failed to calculate filBurnt: %w", err)
|
||||
return api.CirculatingSupply{}, xerrors.Errorf("failed to calculate filBurnt: %w", err)
|
||||
}
|
||||
|
||||
filLocked, err := sm.GetFilLocked(ctx, st)
|
||||
if err != nil {
|
||||
return big.Zero(), xerrors.Errorf("failed to calculate filLocked: %w", err)
|
||||
return api.CirculatingSupply{}, xerrors.Errorf("failed to calculate filLocked: %w", err)
|
||||
}
|
||||
|
||||
ret := types.BigAdd(filVested, filMined)
|
||||
@@ -1022,5 +1106,32 @@ func (sm *StateManager) GetCirculatingSupply(ctx context.Context, height abi.Cha
|
||||
ret = big.Zero()
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
return api.CirculatingSupply{
|
||||
FilVested: filVested,
|
||||
FilMined: filMined,
|
||||
FilBurnt: filBurnt,
|
||||
FilLocked: filLocked,
|
||||
FilCirculating: ret,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (sm *StateManager) GetCirculatingSupply(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (abi.TokenAmount, error) {
|
||||
csi, err := sm.GetCirculatingSupplyDetailed(ctx, height, st)
|
||||
if err != nil {
|
||||
return big.Zero(), err
|
||||
}
|
||||
|
||||
return csi.FilCirculating, nil
|
||||
}
|
||||
|
||||
func (sm *StateManager) GetNtwkVersion(ctx context.Context, height abi.ChainEpoch) runtime.NetworkVersion {
|
||||
if build.UpgradeBreezeHeight == 0 {
|
||||
return runtime.NetworkVersion1
|
||||
}
|
||||
|
||||
if height <= build.UpgradeBreezeHeight {
|
||||
return runtime.NetworkVersion0
|
||||
}
|
||||
|
||||
return runtime.NetworkVersion1
|
||||
}
|
||||
|
||||
+80
-36
@@ -3,8 +3,14 @@ package stmgr
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
saruntime "github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime/proof"
|
||||
|
||||
cid "github.com/ipfs/go-cid"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
@@ -13,8 +19,9 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-bitfield"
|
||||
"github.com/filecoin-project/sector-storage/ffiwrapper"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/account"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/cron"
|
||||
@@ -26,7 +33,6 @@ import (
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/reward"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
@@ -157,13 +163,13 @@ func MinerSectorInfo(ctx context.Context, sm *StateManager, maddr address.Addres
|
||||
return nil, err
|
||||
}
|
||||
if !ok {
|
||||
return nil, xerrors.New("sector not found")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return sectorInfo, nil
|
||||
}
|
||||
|
||||
func GetMinerSectorSet(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address, filter *abi.BitField, filterOut bool) ([]*api.ChainSectorInfo, error) {
|
||||
func GetMinerSectorSet(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address, filter *bitfield.BitField, filterOut bool) ([]*api.ChainSectorInfo, error) {
|
||||
var mas miner.State
|
||||
_, err := sm.LoadActorState(ctx, maddr, &mas, ts)
|
||||
if err != nil {
|
||||
@@ -173,8 +179,8 @@ func GetMinerSectorSet(ctx context.Context, sm *StateManager, ts *types.TipSet,
|
||||
return LoadSectorsFromSet(ctx, sm.ChainStore().Blockstore(), mas.Sectors, filter, filterOut)
|
||||
}
|
||||
|
||||
func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *StateManager, st cid.Cid, maddr address.Address, rand abi.PoStRandomness) ([]abi.SectorInfo, error) {
|
||||
var partsProving []abi.BitField
|
||||
func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *StateManager, st cid.Cid, maddr address.Address, rand abi.PoStRandomness) ([]proof.SectorInfo, error) {
|
||||
var partsProving []bitfield.BitField
|
||||
var mas *miner.State
|
||||
var info *miner.MinerInfo
|
||||
|
||||
@@ -261,7 +267,7 @@ func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *S
|
||||
return nil, xerrors.Errorf("failed to load sectors amt: %w", err)
|
||||
}
|
||||
|
||||
out := make([]abi.SectorInfo, len(ids))
|
||||
out := make([]proof.SectorInfo, len(ids))
|
||||
for i, n := range ids {
|
||||
sid := sectors[n]
|
||||
|
||||
@@ -272,7 +278,7 @@ func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *S
|
||||
return nil, xerrors.Errorf("failed to find sector %d", sid)
|
||||
}
|
||||
|
||||
out[i] = abi.SectorInfo{
|
||||
out[i] = proof.SectorInfo{
|
||||
SealProof: spt,
|
||||
SectorNumber: sinfo.SectorNumber,
|
||||
SealedCID: sinfo.SealedCID,
|
||||
@@ -293,14 +299,8 @@ func StateMinerInfo(ctx context.Context, sm *StateManager, ts *types.TipSet, mad
|
||||
}
|
||||
|
||||
func GetMinerSlashed(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (bool, error) {
|
||||
var mas miner.State
|
||||
_, err := sm.LoadActorState(ctx, maddr, &mas, ts)
|
||||
if err != nil {
|
||||
return false, xerrors.Errorf("(get miner slashed) failed to load miner actor state")
|
||||
}
|
||||
|
||||
var spas power.State
|
||||
_, err = sm.LoadActorState(ctx, builtin.StoragePowerActorAddr, &spas, ts)
|
||||
_, err := sm.LoadActorState(ctx, builtin.StoragePowerActorAddr, &spas, ts)
|
||||
if err != nil {
|
||||
return false, xerrors.Errorf("(get miner slashed) failed to load power actor state")
|
||||
}
|
||||
@@ -393,7 +393,7 @@ func ListMinerActors(ctx context.Context, sm *StateManager, ts *types.TipSet) ([
|
||||
return miners, nil
|
||||
}
|
||||
|
||||
func LoadSectorsFromSet(ctx context.Context, bs blockstore.Blockstore, ssc cid.Cid, filter *abi.BitField, filterOut bool) ([]*api.ChainSectorInfo, error) {
|
||||
func LoadSectorsFromSet(ctx context.Context, bs blockstore.Blockstore, ssc cid.Cid, filter *bitfield.BitField, filterOut bool) ([]*api.ChainSectorInfo, error) {
|
||||
a, err := adt.AsArray(store.ActorStore(ctx, bs), ssc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -438,7 +438,7 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch,
|
||||
return cid.Undef, nil, err
|
||||
}
|
||||
|
||||
r := store.NewChainRand(sm.cs, ts.Cids(), height)
|
||||
r := store.NewChainRand(sm.cs, ts.Cids())
|
||||
vmopt := &vm.VMOpts{
|
||||
StateBase: base,
|
||||
Epoch: height,
|
||||
@@ -446,6 +446,7 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch,
|
||||
Bstore: sm.cs.Blockstore(),
|
||||
Syscalls: sm.cs.VMSys(),
|
||||
CircSupplyCalc: sm.GetCirculatingSupply,
|
||||
NtwkVersion: sm.GetNtwkVersion,
|
||||
BaseFee: ts.Blocks()[0].ParentBaseFee,
|
||||
}
|
||||
vmi, err := vm.NewVM(vmopt)
|
||||
@@ -455,7 +456,7 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch,
|
||||
|
||||
for i := ts.Height(); i < height; i++ {
|
||||
// handle state forks
|
||||
err = sm.handleStateForks(ctx, vmi.StateTree(), i)
|
||||
err = sm.handleStateForks(ctx, vmi.StateTree(), i, ts)
|
||||
if err != nil {
|
||||
return cid.Undef, nil, xerrors.Errorf("error handling state forks: %w", err)
|
||||
}
|
||||
@@ -592,14 +593,14 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcn beacon.RandomBe
|
||||
}, nil
|
||||
}
|
||||
|
||||
type methodMeta struct {
|
||||
type MethodMeta struct {
|
||||
Name string
|
||||
|
||||
Params reflect.Type
|
||||
Ret reflect.Type
|
||||
}
|
||||
|
||||
var MethodsMap = map[cid.Cid][]methodMeta{}
|
||||
var MethodsMap = map[cid.Cid]map[abi.MethodNum]MethodMeta{}
|
||||
|
||||
func init() {
|
||||
cidToMethods := map[cid.Cid][2]interface{}{
|
||||
@@ -617,25 +618,65 @@ func init() {
|
||||
}
|
||||
|
||||
for c, m := range cidToMethods {
|
||||
rt := reflect.TypeOf(m[0])
|
||||
nf := rt.NumField()
|
||||
exports := m[1].(saruntime.Invokee).Exports()
|
||||
methods := make(map[abi.MethodNum]MethodMeta, len(exports))
|
||||
|
||||
MethodsMap[c] = append(MethodsMap[c], methodMeta{
|
||||
// Explicitly add send, it's special.
|
||||
methods[builtin.MethodSend] = MethodMeta{
|
||||
Name: "Send",
|
||||
Params: reflect.TypeOf(new(adt.EmptyValue)),
|
||||
Ret: reflect.TypeOf(new(adt.EmptyValue)),
|
||||
})
|
||||
|
||||
exports := m[1].(abi.Invokee).Exports()
|
||||
for i := 0; i < nf; i++ {
|
||||
export := reflect.TypeOf(exports[i+1])
|
||||
|
||||
MethodsMap[c] = append(MethodsMap[c], methodMeta{
|
||||
Name: rt.Field(i).Name,
|
||||
Params: export.In(1),
|
||||
Ret: export.Out(0),
|
||||
})
|
||||
}
|
||||
|
||||
// Learn method names from the builtin.Methods* structs.
|
||||
rv := reflect.ValueOf(m[0])
|
||||
rt := rv.Type()
|
||||
nf := rt.NumField()
|
||||
methodToName := make([]string, len(exports))
|
||||
for i := 0; i < nf; i++ {
|
||||
name := rt.Field(i).Name
|
||||
number := rv.Field(i).Interface().(abi.MethodNum)
|
||||
methodToName[number] = name
|
||||
}
|
||||
|
||||
// Iterate over exported methods. Some of these _may_ be nil and
|
||||
// must be skipped.
|
||||
for number, export := range exports {
|
||||
if export == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
ev := reflect.ValueOf(export)
|
||||
et := ev.Type()
|
||||
|
||||
// Make sure the method name is correct.
|
||||
// This is just a nice sanity check.
|
||||
fnName := runtime.FuncForPC(ev.Pointer()).Name()
|
||||
fnName = strings.TrimSuffix(fnName[strings.LastIndexByte(fnName, '.')+1:], "-fm")
|
||||
mName := methodToName[number]
|
||||
if mName != fnName {
|
||||
panic(fmt.Sprintf(
|
||||
"actor method name is %s but exported method name is %s",
|
||||
fnName, mName,
|
||||
))
|
||||
}
|
||||
|
||||
switch abi.MethodNum(number) {
|
||||
case builtin.MethodSend:
|
||||
panic("method 0 is reserved for Send")
|
||||
case builtin.MethodConstructor:
|
||||
if fnName != "Constructor" {
|
||||
panic("method 1 is reserved for Constructor")
|
||||
}
|
||||
}
|
||||
|
||||
methods[abi.MethodNum(number)] = MethodMeta{
|
||||
Name: fnName,
|
||||
Params: et.In(1),
|
||||
Ret: et.Out(0),
|
||||
}
|
||||
}
|
||||
MethodsMap[c] = methods
|
||||
}
|
||||
}
|
||||
|
||||
@@ -645,7 +686,10 @@ func GetReturnType(ctx context.Context, sm *StateManager, to address.Address, me
|
||||
return nil, xerrors.Errorf("getting actor: %w", err)
|
||||
}
|
||||
|
||||
m := MethodsMap[act.Code][method]
|
||||
m, found := MethodsMap[act.Code][method]
|
||||
if !found {
|
||||
return nil, fmt.Errorf("unknown method %d for actor %s", method, act.Code)
|
||||
}
|
||||
return reflect.New(m.Ret.Elem()).Interface().(cbg.CBORUnmarshaler), nil
|
||||
}
|
||||
|
||||
|
||||
+37
-5
@@ -3,15 +3,30 @@ package store
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"github.com/ipfs/go-cid"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
func computeNextBaseFee(baseFee types.BigInt, gasLimitUsed int64, noOfBlocks int) types.BigInt {
|
||||
delta := gasLimitUsed/int64(noOfBlocks) - build.BlockGasTarget
|
||||
// deta := 1/PackingEfficiency * gasLimitUsed/noOfBlocks - build.BlockGasTarget
|
||||
// change := baseFee * deta / BlockGasTarget / BaseFeeMaxChangeDenom
|
||||
// nextBaseFee = baseFee + change
|
||||
// nextBaseFee = max(nextBaseFee, build.MinimumBaseFee)
|
||||
|
||||
delta := build.PackingEfficiencyDenom * gasLimitUsed / (int64(noOfBlocks) * build.PackingEfficiencyNum)
|
||||
delta -= build.BlockGasTarget
|
||||
|
||||
// cap change at 12.5% (BaseFeeMaxChangeDenom) by capping delta
|
||||
if delta > build.BlockGasTarget {
|
||||
delta = build.BlockGasTarget
|
||||
}
|
||||
if delta < -build.BlockGasTarget {
|
||||
delta = -build.BlockGasTarget
|
||||
}
|
||||
|
||||
change := big.Mul(baseFee, big.NewInt(delta))
|
||||
change = big.Div(change, big.NewInt(build.BlockGasTarget))
|
||||
@@ -25,18 +40,35 @@ func computeNextBaseFee(baseFee types.BigInt, gasLimitUsed int64, noOfBlocks int
|
||||
}
|
||||
|
||||
func (cs *ChainStore) ComputeBaseFee(ctx context.Context, ts *types.TipSet) (abi.TokenAmount, error) {
|
||||
if ts.Height() > build.UpgradeBreezeHeight && ts.Height() < build.UpgradeBreezeHeight+build.BreezeGasTampingDuration {
|
||||
return abi.NewTokenAmount(100), nil
|
||||
}
|
||||
|
||||
zero := abi.NewTokenAmount(0)
|
||||
|
||||
// totalLimit is sum of GasLimits of unique messages in a tipset
|
||||
totalLimit := int64(0)
|
||||
|
||||
seen := make(map[cid.Cid]struct{})
|
||||
|
||||
for _, b := range ts.Blocks() {
|
||||
msg1, msg2, err := cs.MessagesForBlock(b)
|
||||
if err != nil {
|
||||
return zero, xerrors.Errorf("error getting messages for: %s: %w", b.Cid(), err)
|
||||
}
|
||||
for _, m := range msg1 {
|
||||
totalLimit += m.GasLimit
|
||||
c := m.Cid()
|
||||
if _, ok := seen[c]; !ok {
|
||||
totalLimit += m.GasLimit
|
||||
seen[c] = struct{}{}
|
||||
}
|
||||
}
|
||||
for _, m := range msg2 {
|
||||
totalLimit += m.Message.GasLimit
|
||||
c := m.Cid()
|
||||
if _, ok := seen[c]; !ok {
|
||||
totalLimit += m.Message.GasLimit
|
||||
seen[c] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
parentBaseFee := ts.Blocks()[0].ParentBaseFee
|
||||
|
||||
@@ -18,10 +18,10 @@ func TestBaseFee(t *testing.T) {
|
||||
}{
|
||||
{100e6, 0, 1, 87.5e6},
|
||||
{100e6, 0, 5, 87.5e6},
|
||||
{100e6, build.BlockGasTarget, 1, 100e6},
|
||||
{100e6, build.BlockGasTarget * 2, 2, 100e6},
|
||||
{100e6, build.BlockGasTarget, 1, 103.125e6},
|
||||
{100e6, build.BlockGasTarget * 2, 2, 103.125e6},
|
||||
{100e6, build.BlockGasLimit * 2, 2, 112.5e6},
|
||||
{100e6, build.BlockGasLimit * 1.5, 2, 106.25e6},
|
||||
{100e6, build.BlockGasLimit * 1.5, 2, 110937500},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
@@ -5,11 +5,11 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/chain/gen"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types/mock"
|
||||
"github.com/filecoin-project/lotus/lib/blockstore"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
datastore "github.com/ipfs/go-datastore"
|
||||
syncds "github.com/ipfs/go-datastore/sync"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -42,7 +42,7 @@ func TestIndexSeeks(t *testing.T) {
|
||||
if err := cs.PutTipSet(ctx, mock.TipSet(gen)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cs.SetGenesis(gen)
|
||||
assert.NoError(t, cs.SetGenesis(gen))
|
||||
|
||||
// Put 113 blocks from genesis
|
||||
for i := 0; i < 113; i++ {
|
||||
|
||||
+45
-22
@@ -10,11 +10,11 @@ import (
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/minio/blake2b-simd"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
@@ -49,6 +49,7 @@ var chainHeadKey = dstore.NewKey("head")
|
||||
var blockValidationCacheKeyPrefix = dstore.NewKey("blockValidation")
|
||||
|
||||
var DefaultTipSetCacheSize = 8192
|
||||
var DefaultMsgMetaCacheSize = 2048
|
||||
|
||||
func init() {
|
||||
if s := os.Getenv("LOTUS_CHAIN_TIPSET_CACHE"); s != "" {
|
||||
@@ -58,6 +59,14 @@ func init() {
|
||||
}
|
||||
DefaultTipSetCacheSize = tscs
|
||||
}
|
||||
|
||||
if s := os.Getenv("LOTUS_CHAIN_MSGMETA_CACHE"); s != "" {
|
||||
mmcs, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
log.Errorf("failed to parse 'LOTUS_CHAIN_MSGMETA_CACHE' env var: %s", err)
|
||||
}
|
||||
DefaultMsgMetaCacheSize = mmcs
|
||||
}
|
||||
}
|
||||
|
||||
// ReorgNotifee represents a callback that gets called upon reorgs.
|
||||
@@ -97,7 +106,7 @@ type ChainStore struct {
|
||||
}
|
||||
|
||||
func NewChainStore(bs bstore.Blockstore, ds dstore.Batching, vmcalls vm.SyscallBuilder) *ChainStore {
|
||||
c, _ := lru.NewARC(2048)
|
||||
c, _ := lru.NewARC(DefaultMsgMetaCacheSize)
|
||||
tsc, _ := lru.NewARC(DefaultTipSetCacheSize)
|
||||
cs := &ChainStore{
|
||||
bs: bs,
|
||||
@@ -483,6 +492,10 @@ func (cs *ChainStore) NearestCommonAncestor(a, b *types.TipSet) (*types.TipSet,
|
||||
}
|
||||
|
||||
func (cs *ChainStore) ReorgOps(a, b *types.TipSet) ([]*types.TipSet, []*types.TipSet, error) {
|
||||
return ReorgOps(cs.LoadTipSet, a, b)
|
||||
}
|
||||
|
||||
func ReorgOps(lts func(types.TipSetKey) (*types.TipSet, error), a, b *types.TipSet) ([]*types.TipSet, []*types.TipSet, error) {
|
||||
left := a
|
||||
right := b
|
||||
|
||||
@@ -490,7 +503,7 @@ func (cs *ChainStore) ReorgOps(a, b *types.TipSet) ([]*types.TipSet, []*types.Ti
|
||||
for !left.Equals(right) {
|
||||
if left.Height() > right.Height() {
|
||||
leftChain = append(leftChain, left)
|
||||
par, err := cs.LoadTipSet(left.Parents())
|
||||
par, err := lts(left.Parents())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -498,7 +511,7 @@ func (cs *ChainStore) ReorgOps(a, b *types.TipSet) ([]*types.TipSet, []*types.Ti
|
||||
left = par
|
||||
} else {
|
||||
rightChain = append(rightChain, right)
|
||||
par, err := cs.LoadTipSet(right.Parents())
|
||||
par, err := lts(right.Parents())
|
||||
if err != nil {
|
||||
log.Infof("failed to fetch right.Parents: %s", err)
|
||||
return nil, nil, err
|
||||
@@ -509,6 +522,7 @@ func (cs *ChainStore) ReorgOps(a, b *types.TipSet) ([]*types.TipSet, []*types.Ti
|
||||
}
|
||||
|
||||
return leftChain, rightChain, nil
|
||||
|
||||
}
|
||||
|
||||
// GetHeaviestTipSet returns the current heaviest tipset known (i.e. our head).
|
||||
@@ -829,7 +843,7 @@ type mmCids struct {
|
||||
secpk []cid.Cid
|
||||
}
|
||||
|
||||
func (cs *ChainStore) readMsgMetaCids(mmc cid.Cid) ([]cid.Cid, []cid.Cid, error) {
|
||||
func (cs *ChainStore) ReadMsgMetaCids(mmc cid.Cid) ([]cid.Cid, []cid.Cid, error) {
|
||||
o, ok := cs.mmCache.Get(mmc)
|
||||
if ok {
|
||||
mmcids := o.(*mmCids)
|
||||
@@ -885,7 +899,7 @@ func (cs *ChainStore) GetPath(ctx context.Context, from types.TipSetKey, to type
|
||||
}
|
||||
|
||||
func (cs *ChainStore) MessagesForBlock(b *types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error) {
|
||||
blscids, secpkcids, err := cs.readMsgMetaCids(b.Messages)
|
||||
blscids, secpkcids, err := cs.ReadMsgMetaCids(b.Messages)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -925,7 +939,7 @@ func (cs *ChainStore) LoadMessagesFromCids(cids []cid.Cid) ([]*types.Message, er
|
||||
for i, c := range cids {
|
||||
m, err := cs.GetMessage(c)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to get message: (%s):%d: %w", err, c, i)
|
||||
return nil, xerrors.Errorf("failed to get message: (%s):%d: %w", c, i, err)
|
||||
}
|
||||
|
||||
msgs = append(msgs, m)
|
||||
@@ -939,7 +953,7 @@ func (cs *ChainStore) LoadSignedMessagesFromCids(cids []cid.Cid) ([]*types.Signe
|
||||
for i, c := range cids {
|
||||
m, err := cs.GetSignedMessage(c)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to get message: (%s):%d: %w", err, c, i)
|
||||
return nil, xerrors.Errorf("failed to get message: (%s):%d: %w", c, i, err)
|
||||
}
|
||||
|
||||
msgs = append(msgs, m)
|
||||
@@ -1109,7 +1123,7 @@ func (cs *ChainStore) GetTipsetByHeight(ctx context.Context, h abi.ChainEpoch, t
|
||||
return cs.LoadTipSet(lbts.Parents())
|
||||
}
|
||||
|
||||
func recurseLinks(bs bstore.Blockstore, root cid.Cid, in []cid.Cid) ([]cid.Cid, error) {
|
||||
func recurseLinks(bs bstore.Blockstore, walked *cid.Set, root cid.Cid, in []cid.Cid) ([]cid.Cid, error) {
|
||||
if root.Prefix().Codec != cid.DagCBOR {
|
||||
return in, nil
|
||||
}
|
||||
@@ -1126,9 +1140,14 @@ func recurseLinks(bs bstore.Blockstore, root cid.Cid, in []cid.Cid) ([]cid.Cid,
|
||||
return
|
||||
}
|
||||
|
||||
// traversed this already...
|
||||
if !walked.Visit(c) {
|
||||
return
|
||||
}
|
||||
|
||||
in = append(in, c)
|
||||
var err error
|
||||
in, err = recurseLinks(bs, c, in)
|
||||
in, err = recurseLinks(bs, walked, c, in)
|
||||
if err != nil {
|
||||
rerr = err
|
||||
}
|
||||
@@ -1140,12 +1159,13 @@ func recurseLinks(bs bstore.Blockstore, root cid.Cid, in []cid.Cid) ([]cid.Cid,
|
||||
return in, rerr
|
||||
}
|
||||
|
||||
func (cs *ChainStore) Export(ctx context.Context, ts *types.TipSet, w io.Writer) error {
|
||||
func (cs *ChainStore) Export(ctx context.Context, ts *types.TipSet, inclRecentRoots abi.ChainEpoch, w io.Writer) error {
|
||||
if ts == nil {
|
||||
ts = cs.GetHeaviestTipSet()
|
||||
}
|
||||
|
||||
seen := cid.NewSet()
|
||||
walked := cid.NewSet()
|
||||
|
||||
h := &car.CarHeader{
|
||||
Roots: ts.Cids(),
|
||||
@@ -1177,19 +1197,24 @@ func (cs *ChainStore) Export(ctx context.Context, ts *types.TipSet, w io.Writer)
|
||||
return xerrors.Errorf("unmarshaling block header (cid=%s): %w", blk, err)
|
||||
}
|
||||
|
||||
for _, p := range b.Parents {
|
||||
blocksToWalk = append(blocksToWalk, p)
|
||||
}
|
||||
|
||||
cids, err := recurseLinks(cs.bs, b.Messages, []cid.Cid{b.Messages})
|
||||
cids, err := recurseLinks(cs.bs, walked, b.Messages, []cid.Cid{b.Messages})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("recursing messages failed: %w", err)
|
||||
}
|
||||
|
||||
if b.Height > 0 {
|
||||
for _, p := range b.Parents {
|
||||
blocksToWalk = append(blocksToWalk, p)
|
||||
}
|
||||
} else {
|
||||
// include the genesis block
|
||||
cids = append(cids, b.Parents...)
|
||||
}
|
||||
|
||||
out := cids
|
||||
|
||||
if b.Height == 0 {
|
||||
cids, err := recurseLinks(cs.bs, b.ParentStateRoot, []cid.Cid{b.ParentStateRoot})
|
||||
if b.Height == 0 || b.Height > ts.Height()-inclRecentRoots {
|
||||
cids, err := recurseLinks(cs.bs, walked, b.ParentStateRoot, []cid.Cid{b.ParentStateRoot})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("recursing genesis state failed: %w", err)
|
||||
}
|
||||
@@ -1272,14 +1297,12 @@ func (cs *ChainStore) GetLatestBeaconEntry(ts *types.TipSet) (*types.BeaconEntry
|
||||
type chainRand struct {
|
||||
cs *ChainStore
|
||||
blks []cid.Cid
|
||||
bh abi.ChainEpoch
|
||||
}
|
||||
|
||||
func NewChainRand(cs *ChainStore, blks []cid.Cid, bheight abi.ChainEpoch) vm.Rand {
|
||||
func NewChainRand(cs *ChainStore, blks []cid.Cid) vm.Rand {
|
||||
return &chainRand{
|
||||
cs: cs,
|
||||
blks: blks,
|
||||
bh: bheight,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,12 +7,12 @@ import (
|
||||
|
||||
datastore "github.com/ipfs/go-datastore"
|
||||
|
||||
"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/miner"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/gen"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
@@ -96,7 +96,7 @@ func TestChainExportImport(t *testing.T) {
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
if err := cg.ChainStore().Export(context.TODO(), last, buf); err != nil {
|
||||
if err := cg.ChainStore().Export(context.TODO(), last, 0, buf); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@ import (
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
big2 "github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
big2 "github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
@@ -41,7 +41,7 @@ func (cs *ChainStore) Weight(ctx context.Context, ts *types.TipSet) (types.BigIn
|
||||
|
||||
var st power.State
|
||||
if err := cst.Get(ctx, act.Head, &st); err != nil {
|
||||
return types.NewInt(0), xerrors.Errorf("get power actor head: %w", err)
|
||||
return types.NewInt(0), xerrors.Errorf("get power actor head (%s, height=%d): %w", act.Head, ts.Height(), err)
|
||||
}
|
||||
tpow = st.TotalQualityAdjPower // TODO: REVIEW: Is this correct?
|
||||
}
|
||||
|
||||
+139
-42
@@ -3,6 +3,7 @@ package sub
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -40,6 +41,9 @@ import (
|
||||
|
||||
var log = logging.Logger("sub")
|
||||
|
||||
var ErrSoftFailure = errors.New("soft validation failure")
|
||||
var ErrInsufficientPower = errors.New("incoming block's miner does not have minimum power")
|
||||
|
||||
func HandleIncomingBlocks(ctx context.Context, bsub *pubsub.Subscription, s *chain.Syncer, bserv bserv.BlockService, cmgr connmgr.ConnManager) {
|
||||
for {
|
||||
msg, err := bsub.Next(ctx)
|
||||
@@ -195,6 +199,8 @@ func fetchCids(
|
||||
}
|
||||
|
||||
type BlockValidator struct {
|
||||
self peer.ID
|
||||
|
||||
peers *lru.TwoQueueCache
|
||||
|
||||
killThresh int
|
||||
@@ -211,9 +217,10 @@ type BlockValidator struct {
|
||||
keycache map[string]address.Address
|
||||
}
|
||||
|
||||
func NewBlockValidator(chain *store.ChainStore, stmgr *stmgr.StateManager, blacklist func(peer.ID)) *BlockValidator {
|
||||
func NewBlockValidator(self peer.ID, chain *store.ChainStore, stmgr *stmgr.StateManager, blacklist func(peer.ID)) *BlockValidator {
|
||||
p, _ := lru.New2Q(4096)
|
||||
return &BlockValidator{
|
||||
self: self,
|
||||
peers: p,
|
||||
killThresh: 10,
|
||||
blacklist: blacklist,
|
||||
@@ -243,6 +250,10 @@ func (bv *BlockValidator) flagPeer(p peer.ID) {
|
||||
}
|
||||
|
||||
func (bv *BlockValidator) Validate(ctx context.Context, pid peer.ID, msg *pubsub.Message) pubsub.ValidationResult {
|
||||
if pid == bv.self {
|
||||
return bv.validateLocalBlock(ctx, msg)
|
||||
}
|
||||
|
||||
// track validation time
|
||||
begin := build.Clock.Now()
|
||||
defer func() {
|
||||
@@ -251,31 +262,15 @@ func (bv *BlockValidator) Validate(ctx context.Context, pid peer.ID, msg *pubsub
|
||||
|
||||
stats.Record(ctx, metrics.BlockReceived.M(1))
|
||||
|
||||
recordFailure := func(what string) {
|
||||
ctx, _ = tag.New(ctx, tag.Insert(metrics.FailureType, what))
|
||||
stats.Record(ctx, metrics.BlockValidationFailure.M(1))
|
||||
recordFailureFlagPeer := func(what string) {
|
||||
recordFailure(ctx, metrics.BlockValidationFailure, what)
|
||||
bv.flagPeer(pid)
|
||||
}
|
||||
|
||||
// make sure the block can be decoded
|
||||
blk, err := types.DecodeBlockMsg(msg.GetData())
|
||||
blk, what, err := bv.decodeAndCheckBlock(msg)
|
||||
if err != nil {
|
||||
log.Error("got invalid block over pubsub: ", err)
|
||||
recordFailure("invalid")
|
||||
return pubsub.ValidationReject
|
||||
}
|
||||
|
||||
// check the message limit constraints
|
||||
if len(blk.BlsMessages)+len(blk.SecpkMessages) > build.BlockMessageLimit {
|
||||
log.Warnf("received block with too many messages over pubsub")
|
||||
recordFailure("too_many_messages")
|
||||
return pubsub.ValidationReject
|
||||
}
|
||||
|
||||
// make sure we have a signature
|
||||
if blk.Header.BlockSig == nil {
|
||||
log.Warnf("received block without a signature over pubsub")
|
||||
recordFailure("missing_signature")
|
||||
recordFailureFlagPeer(what)
|
||||
return pubsub.ValidationReject
|
||||
}
|
||||
|
||||
@@ -283,7 +278,7 @@ func (bv *BlockValidator) Validate(ctx context.Context, pid peer.ID, msg *pubsub
|
||||
err = bv.validateMsgMeta(ctx, blk)
|
||||
if err != nil {
|
||||
log.Warnf("error validating message metadata: %s", err)
|
||||
recordFailure("invalid_block_meta")
|
||||
recordFailureFlagPeer("invalid_block_meta")
|
||||
return pubsub.ValidationReject
|
||||
}
|
||||
|
||||
@@ -296,26 +291,26 @@ func (bv *BlockValidator) Validate(ctx context.Context, pid peer.ID, msg *pubsub
|
||||
// if we are synced and the miner is unknown, then the block is rejcected.
|
||||
key, err := bv.checkPowerAndGetWorkerKey(ctx, blk.Header)
|
||||
if err != nil {
|
||||
if bv.isChainNearSynced() {
|
||||
if err != ErrSoftFailure && bv.isChainNearSynced() {
|
||||
log.Warnf("received block from unknown miner or miner that doesn't meet min power over pubsub; rejecting message")
|
||||
recordFailure("unknown_miner")
|
||||
recordFailureFlagPeer("unknown_miner")
|
||||
return pubsub.ValidationReject
|
||||
} else {
|
||||
log.Warnf("cannot validate block message; unknown miner or miner that doesn't meet min power in unsynced chain")
|
||||
return pubsub.ValidationIgnore
|
||||
}
|
||||
|
||||
log.Warnf("cannot validate block message; unknown miner or miner that doesn't meet min power in unsynced chain")
|
||||
return pubsub.ValidationIgnore
|
||||
}
|
||||
|
||||
err = sigs.CheckBlockSignature(ctx, blk.Header, key)
|
||||
if err != nil {
|
||||
log.Errorf("block signature verification failed: %s", err)
|
||||
recordFailure("signature_verification_failed")
|
||||
recordFailureFlagPeer("signature_verification_failed")
|
||||
return pubsub.ValidationReject
|
||||
}
|
||||
|
||||
if blk.Header.ElectionProof.WinCount < 1 {
|
||||
log.Errorf("block is not claiming to be winning")
|
||||
recordFailure("not_winning")
|
||||
recordFailureFlagPeer("not_winning")
|
||||
return pubsub.ValidationReject
|
||||
}
|
||||
|
||||
@@ -332,12 +327,50 @@ func (bv *BlockValidator) Validate(ctx context.Context, pid peer.ID, msg *pubsub
|
||||
return pubsub.ValidationAccept
|
||||
}
|
||||
|
||||
func (bv *BlockValidator) validateLocalBlock(ctx context.Context, msg *pubsub.Message) pubsub.ValidationResult {
|
||||
stats.Record(ctx, metrics.BlockPublished.M(1))
|
||||
|
||||
blk, what, err := bv.decodeAndCheckBlock(msg)
|
||||
if err != nil {
|
||||
log.Errorf("got invalid local block: %s", err)
|
||||
ctx, _ = tag.New(ctx, tag.Insert(metrics.FailureType, what))
|
||||
stats.Record(ctx, metrics.BlockValidationFailure.M(1))
|
||||
return pubsub.ValidationIgnore
|
||||
}
|
||||
|
||||
if count := bv.recvBlocks.add(blk.Header.Cid()); count > 0 {
|
||||
log.Warnf("local block has been seen %d times; ignoring", count)
|
||||
return pubsub.ValidationIgnore
|
||||
}
|
||||
|
||||
msg.ValidatorData = blk
|
||||
stats.Record(ctx, metrics.BlockValidationSuccess.M(1))
|
||||
return pubsub.ValidationAccept
|
||||
}
|
||||
|
||||
func (bv *BlockValidator) decodeAndCheckBlock(msg *pubsub.Message) (*types.BlockMsg, string, error) {
|
||||
blk, err := types.DecodeBlockMsg(msg.GetData())
|
||||
if err != nil {
|
||||
return nil, "invalid", xerrors.Errorf("error decoding block: %w", err)
|
||||
}
|
||||
|
||||
if count := len(blk.BlsMessages) + len(blk.SecpkMessages); count > build.BlockMessageLimit {
|
||||
return nil, "too_many_messages", fmt.Errorf("block contains too many messages (%d)", count)
|
||||
}
|
||||
|
||||
// make sure we have a signature
|
||||
if blk.Header.BlockSig == nil {
|
||||
return nil, "missing_signature", fmt.Errorf("block without a signature")
|
||||
}
|
||||
|
||||
return blk, "", nil
|
||||
}
|
||||
|
||||
func (bv *BlockValidator) isChainNearSynced() bool {
|
||||
ts := bv.chain.GetHeaviestTipSet()
|
||||
timestamp := ts.MinTimestamp()
|
||||
now := build.Clock.Now().UnixNano()
|
||||
cutoff := uint64(now) - uint64(6*time.Hour)
|
||||
return timestamp > cutoff
|
||||
timestampTime := time.Unix(int64(timestamp), 0)
|
||||
return build.Clock.Since(timestampTime) < 6*time.Hour
|
||||
}
|
||||
|
||||
func (bv *BlockValidator) validateMsgMeta(ctx context.Context, msg *types.BlockMsg) error {
|
||||
@@ -443,19 +476,19 @@ func (bv *BlockValidator) checkPowerAndGetWorkerKey(ctx context.Context, bh *typ
|
||||
baseTs := bv.chain.GetHeaviestTipSet()
|
||||
lbts, err := stmgr.GetLookbackTipSetForRound(ctx, bv.stmgr, baseTs, bh.Height)
|
||||
if err != nil {
|
||||
log.Warnf("failed to load lookback tipset for incoming block")
|
||||
return address.Undef, err
|
||||
log.Warnf("failed to load lookback tipset for incoming block: %s", err)
|
||||
return address.Undef, ErrSoftFailure
|
||||
}
|
||||
|
||||
hmp, err := stmgr.MinerHasMinPower(ctx, bv.stmgr, bh.Miner, lbts)
|
||||
if err != nil {
|
||||
log.Warnf("failed to determine if incoming block's miner has minimum power")
|
||||
return address.Undef, err
|
||||
log.Warnf("failed to determine if incoming block's miner has minimum power: %s", err)
|
||||
return address.Undef, ErrSoftFailure
|
||||
}
|
||||
|
||||
if !hmp {
|
||||
log.Warnf("incoming block's miner does not have minimum power")
|
||||
return address.Undef, xerrors.New("incoming block's miner does not have minimum power")
|
||||
return address.Undef, ErrInsufficientPower
|
||||
}
|
||||
|
||||
return key, nil
|
||||
@@ -485,14 +518,19 @@ func (brc *blockReceiptCache) add(bcid cid.Cid) int {
|
||||
}
|
||||
|
||||
type MessageValidator struct {
|
||||
self peer.ID
|
||||
mpool *messagepool.MessagePool
|
||||
}
|
||||
|
||||
func NewMessageValidator(mp *messagepool.MessagePool) *MessageValidator {
|
||||
return &MessageValidator{mp}
|
||||
func NewMessageValidator(self peer.ID, mp *messagepool.MessagePool) *MessageValidator {
|
||||
return &MessageValidator{self: self, mpool: mp}
|
||||
}
|
||||
|
||||
func (mv *MessageValidator) Validate(ctx context.Context, pid peer.ID, msg *pubsub.Message) pubsub.ValidationResult {
|
||||
if pid == mv.self {
|
||||
return mv.validateLocalMessage(ctx, msg)
|
||||
}
|
||||
|
||||
stats.Record(ctx, metrics.MessageReceived.M(1))
|
||||
m, err := types.DecodeSignedMessage(msg.Message.GetData())
|
||||
if err != nil {
|
||||
@@ -506,11 +544,19 @@ func (mv *MessageValidator) Validate(ctx context.Context, pid peer.ID, msg *pubs
|
||||
log.Debugf("failed to add message from network to message pool (From: %s, To: %s, Nonce: %d, Value: %s): %s", m.Message.From, m.Message.To, m.Message.Nonce, types.FIL(m.Message.Value), err)
|
||||
ctx, _ = tag.New(
|
||||
ctx,
|
||||
tag.Insert(metrics.FailureType, "add"),
|
||||
tag.Upsert(metrics.Local, "false"),
|
||||
)
|
||||
stats.Record(ctx, metrics.MessageValidationFailure.M(1))
|
||||
recordFailure(ctx, metrics.MessageValidationFailure, "add")
|
||||
switch {
|
||||
case xerrors.Is(err, messagepool.ErrBroadcastAnyway) || xerrors.Is(err, messagepool.ErrRBFTooLowPremium):
|
||||
case xerrors.Is(err, messagepool.ErrSoftValidationFailure):
|
||||
fallthrough
|
||||
case xerrors.Is(err, messagepool.ErrRBFTooLowPremium):
|
||||
fallthrough
|
||||
case xerrors.Is(err, messagepool.ErrTooManyPendingMessages):
|
||||
fallthrough
|
||||
case xerrors.Is(err, messagepool.ErrNonceGap):
|
||||
fallthrough
|
||||
case xerrors.Is(err, messagepool.ErrNonceTooLow):
|
||||
return pubsub.ValidationIgnore
|
||||
default:
|
||||
return pubsub.ValidationReject
|
||||
@@ -520,6 +566,49 @@ func (mv *MessageValidator) Validate(ctx context.Context, pid peer.ID, msg *pubs
|
||||
return pubsub.ValidationAccept
|
||||
}
|
||||
|
||||
func (mv *MessageValidator) validateLocalMessage(ctx context.Context, msg *pubsub.Message) pubsub.ValidationResult {
|
||||
ctx, _ = tag.New(
|
||||
ctx,
|
||||
tag.Upsert(metrics.Local, "true"),
|
||||
)
|
||||
// do some lightweight validation
|
||||
stats.Record(ctx, metrics.MessagePublished.M(1))
|
||||
|
||||
m, err := types.DecodeSignedMessage(msg.Message.GetData())
|
||||
if err != nil {
|
||||
log.Warnf("failed to decode local message: %s", err)
|
||||
recordFailure(ctx, metrics.MessageValidationFailure, "decode")
|
||||
return pubsub.ValidationIgnore
|
||||
}
|
||||
|
||||
if m.Size() > 32*1024 {
|
||||
log.Warnf("local message is too large! (%dB)", m.Size())
|
||||
recordFailure(ctx, metrics.MessageValidationFailure, "oversize")
|
||||
return pubsub.ValidationIgnore
|
||||
}
|
||||
|
||||
if m.Message.To == address.Undef {
|
||||
log.Warn("local message has invalid destination address")
|
||||
recordFailure(ctx, metrics.MessageValidationFailure, "undef-addr")
|
||||
return pubsub.ValidationIgnore
|
||||
}
|
||||
|
||||
if !m.Message.Value.LessThan(types.TotalFilecoinInt) {
|
||||
log.Warnf("local messages has too high value: %s", m.Message.Value)
|
||||
recordFailure(ctx, metrics.MessageValidationFailure, "value-too-high")
|
||||
return pubsub.ValidationIgnore
|
||||
}
|
||||
|
||||
if err := mv.mpool.VerifyMsgSig(m); err != nil {
|
||||
log.Warnf("signature verification failed for local message: %s", err)
|
||||
recordFailure(ctx, metrics.MessageValidationFailure, "verify-sig")
|
||||
return pubsub.ValidationIgnore
|
||||
}
|
||||
|
||||
stats.Record(ctx, metrics.MessageValidationSuccess.M(1))
|
||||
return pubsub.ValidationAccept
|
||||
}
|
||||
|
||||
func HandleIncomingMessages(ctx context.Context, mpool *messagepool.MessagePool, msub *pubsub.Subscription) {
|
||||
for {
|
||||
_, err := msub.Next(ctx)
|
||||
@@ -535,3 +624,11 @@ func HandleIncomingMessages(ctx context.Context, mpool *messagepool.MessagePool,
|
||||
// Do nothing... everything happens in validate
|
||||
}
|
||||
}
|
||||
|
||||
func recordFailure(ctx context.Context, metric *stats.Int64Measure, failureType string) {
|
||||
ctx, _ = tag.New(
|
||||
ctx,
|
||||
tag.Upsert(metrics.FailureType, failureType),
|
||||
)
|
||||
stats.Record(ctx, metric.M(1))
|
||||
}
|
||||
|
||||
+76
-6
@@ -7,9 +7,12 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime/proof"
|
||||
|
||||
"github.com/Gurpartap/async"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/ipfs/go-cid"
|
||||
@@ -24,11 +27,11 @@ import (
|
||||
"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/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
blst "github.com/supranational/blst/bindings/go"
|
||||
|
||||
@@ -52,6 +55,19 @@ import (
|
||||
//the theoretical max height based on systime are quickly rejected
|
||||
const MaxHeightDrift = 5
|
||||
|
||||
var defaultMessageFetchWindowSize = 200
|
||||
|
||||
func init() {
|
||||
if s := os.Getenv("LOTUS_BSYNC_MSG_WINDOW"); s != "" {
|
||||
val, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
log.Errorf("failed to parse LOTUS_BSYNC_MSG_WINDOW: %s", err)
|
||||
return
|
||||
}
|
||||
defaultMessageFetchWindowSize = val
|
||||
}
|
||||
}
|
||||
|
||||
var log = logging.Logger("chain")
|
||||
|
||||
var LocalIncoming = "incoming"
|
||||
@@ -109,6 +125,10 @@ type Syncer struct {
|
||||
receiptTracker *blockReceiptTracker
|
||||
|
||||
verifier ffiwrapper.Verifier
|
||||
|
||||
windowSize int
|
||||
|
||||
tickerCtxCancel context.CancelFunc
|
||||
}
|
||||
|
||||
// NewSyncer creates a new Syncer object.
|
||||
@@ -134,6 +154,7 @@ func NewSyncer(sm *stmgr.StateManager, bsync *blocksync.BlockSync, connmgr connm
|
||||
receiptTracker: newBlockReceiptTracker(),
|
||||
connmgr: connmgr,
|
||||
verifier: verifier,
|
||||
windowSize: defaultMessageFetchWindowSize,
|
||||
|
||||
incoming: pubsub.New(50),
|
||||
}
|
||||
@@ -149,11 +170,35 @@ func NewSyncer(sm *stmgr.StateManager, bsync *blocksync.BlockSync, connmgr connm
|
||||
}
|
||||
|
||||
func (syncer *Syncer) Start() {
|
||||
tickerCtx, tickerCtxCancel := context.WithCancel(context.Background())
|
||||
syncer.syncmgr.Start()
|
||||
|
||||
syncer.tickerCtxCancel = tickerCtxCancel
|
||||
|
||||
go syncer.runMetricsTricker(tickerCtx)
|
||||
}
|
||||
|
||||
func (syncer *Syncer) runMetricsTricker(tickerCtx context.Context) {
|
||||
genesisTime := time.Unix(int64(syncer.Genesis.MinTimestamp()), 0)
|
||||
ticker := build.Clock.Ticker(time.Duration(build.BlockDelaySecs) * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
sinceGenesis := build.Clock.Now().Sub(genesisTime)
|
||||
expectedHeight := int64(sinceGenesis.Seconds()) / int64(build.BlockDelaySecs)
|
||||
|
||||
stats.Record(tickerCtx, metrics.ChainNodeHeightExpected.M(expectedHeight))
|
||||
case <-tickerCtx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (syncer *Syncer) Stop() {
|
||||
syncer.syncmgr.Stop()
|
||||
syncer.tickerCtxCancel()
|
||||
}
|
||||
|
||||
// InformNewHead informs the syncer about a new potential tipset
|
||||
@@ -641,7 +686,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er
|
||||
validationStart := build.Clock.Now()
|
||||
defer func() {
|
||||
stats.Record(ctx, metrics.BlockValidationDurationMilliseconds.M(metrics.SinceInMilliseconds(validationStart)))
|
||||
log.Infow("block validation", "took", time.Since(validationStart), "height", b.Header.Height)
|
||||
log.Infow("block validation", "took", time.Since(validationStart), "height", b.Header.Height, "age", time.Since(time.Unix(int64(b.Header.Timestamp), 0)))
|
||||
}()
|
||||
|
||||
ctx, span := trace.StartSpan(ctx, "validateBlock")
|
||||
@@ -936,7 +981,7 @@ func (syncer *Syncer) VerifyWinningPoStProof(ctx context.Context, h *types.Block
|
||||
return xerrors.Errorf("getting winning post sector set: %w", err)
|
||||
}
|
||||
|
||||
ok, err := ffiwrapper.ProofVerifier.VerifyWinningPoSt(ctx, abi.WinningPoStVerifyInfo{
|
||||
ok, err := ffiwrapper.ProofVerifier.VerifyWinningPoSt(ctx, proof.WinningPoStVerifyInfo{
|
||||
Randomness: rand,
|
||||
Proofs: h.WinPoStProof,
|
||||
ChallengedSectors: sectors,
|
||||
@@ -1394,12 +1439,14 @@ func (syncer *Syncer) syncMessagesAndCheckState(ctx context.Context, headers []*
|
||||
|
||||
// fills out each of the given tipsets with messages and calls the callback with it
|
||||
func (syncer *Syncer) iterFullTipsets(ctx context.Context, headers []*types.TipSet, cb func(context.Context, *store.FullTipSet) error) error {
|
||||
ss := extractSyncState(ctx)
|
||||
ctx, span := trace.StartSpan(ctx, "iterFullTipsets")
|
||||
defer span.End()
|
||||
|
||||
span.AddAttributes(trace.Int64Attribute("num_headers", int64(len(headers))))
|
||||
|
||||
windowSize := 200
|
||||
windowSize := syncer.windowSize
|
||||
mainLoop:
|
||||
for i := len(headers) - 1; i >= 0; {
|
||||
fts, err := syncer.store.TryFillTipSet(headers[i])
|
||||
if err != nil {
|
||||
@@ -1420,6 +1467,7 @@ func (syncer *Syncer) iterFullTipsets(ctx context.Context, headers []*types.TipS
|
||||
|
||||
nextI := (i + 1) - batchSize // want to fetch batchSize values, 'i' points to last one we want to fetch, so its 'inclusive' of our request, thus we need to add one to our request start index
|
||||
|
||||
ss.SetStage(api.StageFetchingMessages)
|
||||
var bstout []*blocksync.CompactedMessages
|
||||
for len(bstout) < batchSize {
|
||||
next := headers[nextI]
|
||||
@@ -1427,12 +1475,19 @@ func (syncer *Syncer) iterFullTipsets(ctx context.Context, headers []*types.TipS
|
||||
nreq := batchSize - len(bstout)
|
||||
bstips, err := syncer.Bsync.GetChainMessages(ctx, next, uint64(nreq))
|
||||
if err != nil {
|
||||
// TODO check errors for temporary nature
|
||||
if windowSize > 1 {
|
||||
windowSize /= 2
|
||||
log.Infof("error fetching messages: %s; reducing window size to %d and trying again", err, windowSize)
|
||||
continue mainLoop
|
||||
}
|
||||
return xerrors.Errorf("message processing failed: %w", err)
|
||||
}
|
||||
|
||||
bstout = append(bstout, bstips...)
|
||||
nextI += len(bstips)
|
||||
}
|
||||
ss.SetStage(api.StageMessages)
|
||||
|
||||
for bsi := 0; bsi < len(bstout); bsi++ {
|
||||
// temp storage so we don't persist data we dont want to
|
||||
@@ -1461,9 +1516,24 @@ func (syncer *Syncer) iterFullTipsets(ctx context.Context, headers []*types.TipS
|
||||
return xerrors.Errorf("message processing failed: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if i >= windowSize {
|
||||
newWindowSize := windowSize + 10
|
||||
if newWindowSize > int(blocksync.MaxRequestLength) {
|
||||
newWindowSize = int(blocksync.MaxRequestLength)
|
||||
}
|
||||
if newWindowSize > windowSize {
|
||||
windowSize = newWindowSize
|
||||
log.Infof("successfully fetched %d messages; increasing window size to %d", len(bstout), windowSize)
|
||||
}
|
||||
}
|
||||
|
||||
i -= batchSize
|
||||
}
|
||||
|
||||
// remember our window size
|
||||
syncer.windowSize = windowSize
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -343,12 +343,12 @@ func (sm *SyncManager) scheduleProcessResult(res *syncResult) {
|
||||
sm.syncQueue.buckets = append(sm.syncQueue.buckets, relbucket)
|
||||
}
|
||||
return
|
||||
} else {
|
||||
// TODO: this is the case where we try to sync a chain, and
|
||||
// fail, and we have more blocks on top of that chain that
|
||||
// have come in since. The question is, should we try to
|
||||
// sync these? or just drop them?
|
||||
}
|
||||
// TODO: this is the case where we try to sync a chain, and
|
||||
// fail, and we have more blocks on top of that chain that
|
||||
// have come in since. The question is, should we try to
|
||||
// sync these? or just drop them?
|
||||
log.Error("failed to sync chain but have new unconnected blocks from chain")
|
||||
}
|
||||
|
||||
if sm.nextSyncTarget == nil && !sm.syncQueue.Empty() {
|
||||
|
||||
+14
-22
@@ -3,11 +3,14 @@ package chain_test
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/ipfs/go-cid"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime/proof"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
ds "github.com/ipfs/go-datastore"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
@@ -15,8 +18,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/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"
|
||||
@@ -36,7 +39,10 @@ import (
|
||||
|
||||
func init() {
|
||||
build.InsecurePoStValidation = true
|
||||
os.Setenv("TRUST_PARAMS", "1")
|
||||
err := os.Setenv("TRUST_PARAMS", "1")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
|
||||
abi.RegisteredSealProof_StackedDrg2KiBV1: {},
|
||||
}
|
||||
@@ -212,20 +218,6 @@ func (tu *syncTestUtil) mineNewBlock(src int, miners []int) {
|
||||
tu.g.CurTipset = mts
|
||||
}
|
||||
|
||||
func fblkToBlkMsg(fb *types.FullBlock) *types.BlockMsg {
|
||||
out := &types.BlockMsg{
|
||||
Header: fb.Header,
|
||||
}
|
||||
|
||||
for _, msg := range fb.BlsMessages {
|
||||
out.BlsMessages = append(out.BlsMessages, msg.Cid())
|
||||
}
|
||||
for _, msg := range fb.SecpkMessages {
|
||||
out.SecpkMessages = append(out.SecpkMessages, msg.Cid())
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (tu *syncTestUtil) addSourceNode(gen int) {
|
||||
if tu.genesis != nil {
|
||||
tu.t.Fatal("source node already exists")
|
||||
@@ -452,9 +444,9 @@ func (wpp badWpp) GenerateCandidates(context.Context, abi.PoStRandomness, uint64
|
||||
return []uint64{1}, nil
|
||||
}
|
||||
|
||||
func (wpp badWpp) ComputeProof(context.Context, []abi.SectorInfo, abi.PoStRandomness) ([]abi.PoStProof, error) {
|
||||
return []abi.PoStProof{
|
||||
abi.PoStProof{
|
||||
func (wpp badWpp) ComputeProof(context.Context, []proof.SectorInfo, abi.PoStRandomness) ([]proof.PoStProof, error) {
|
||||
return []proof.PoStProof{
|
||||
{
|
||||
PoStProof: abi.RegisteredPoStProof_StackedDrgWinning2KiBV1,
|
||||
ProofBytes: []byte("evil"),
|
||||
},
|
||||
@@ -587,7 +579,7 @@ func TestDuplicateNonce(t *testing.T) {
|
||||
|
||||
msgs := make([][]*types.SignedMessage, 2)
|
||||
// Each miner includes a message from the banker with the same nonce, but to different addresses
|
||||
for k, _ := range msgs {
|
||||
for k := range msgs {
|
||||
msgs[k] = []*types.SignedMessage{makeMsg(tu.g.Miners[k])}
|
||||
}
|
||||
|
||||
|
||||
+1
-19
@@ -1,34 +1,16 @@
|
||||
package chain
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
func SyncStageString(v api.SyncStateStage) string {
|
||||
switch v {
|
||||
case api.StageHeaders:
|
||||
return "header sync"
|
||||
case api.StagePersistHeaders:
|
||||
return "persisting headers"
|
||||
case api.StageMessages:
|
||||
return "message sync"
|
||||
case api.StageSyncComplete:
|
||||
return "complete"
|
||||
case api.StageSyncErrored:
|
||||
return "error"
|
||||
default:
|
||||
return fmt.Sprintf("<unknown: %d>", v)
|
||||
}
|
||||
}
|
||||
|
||||
type SyncerState struct {
|
||||
lk sync.Mutex
|
||||
Target *types.TipSet
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
big2 "github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
big2 "github.com/filecoin-project/go-state-types/big"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user