Compare commits
533
Commits
interop.6.1
...
v0.4.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5de7b62dbc | ||
|
|
5fb76ddad2 | ||
|
|
cc02092aae | ||
|
|
3e4b80e7f6 | ||
|
|
14ae8c7272 | ||
|
|
567b8082c3 | ||
|
|
f3f92ce5bc | ||
|
|
c4158f12f1 | ||
|
|
3429941639 | ||
|
|
11dc902d53 | ||
|
|
41b775fdd4 | ||
|
|
e9d2a3edd9 | ||
|
|
42696372ee | ||
|
|
39625eada7 | ||
|
|
7a7e5a85ad | ||
|
|
254295b9c3 | ||
|
|
4dd79ec6fa | ||
|
|
9ccd25b072 | ||
|
|
5e7f561133 | ||
|
|
c68a8f802e | ||
|
|
29f5f451b3 | ||
|
|
2caa7164a6 | ||
|
|
21148033e2 | ||
|
|
bc88c632d1 | ||
|
|
1e17ea3fff | ||
|
|
ca7e5f5e16 | ||
|
|
cd2595da67 | ||
|
|
3a9f1bf9a2 | ||
|
|
9094405537 | ||
|
|
4db61e71da | ||
|
|
a6417dc24b | ||
|
|
1bc9fbca20 | ||
|
|
369ec8221f | ||
|
|
052fc35a91 | ||
|
|
b8ab549bcb | ||
|
|
4f60c1afe7 | ||
|
|
9cd34509ee | ||
|
|
a2fd0aad41 | ||
|
|
01ac4e5da3 | ||
|
|
01e230e810 | ||
|
|
78ee64d9f8 | ||
|
|
e5a7cb635c | ||
|
|
49ddcdb4b0 | ||
|
|
b5ae3c055b | ||
|
|
9712bbc854 | ||
|
|
3134fcb54a | ||
|
|
87d668390e | ||
|
|
710286d6e7 | ||
|
|
04edeccbf4 | ||
|
|
db5929f4a5 | ||
|
|
e65215f1b5 | ||
|
|
c97720e731 | ||
|
|
3aaa4fb692 | ||
|
|
7e1e9bcd60 | ||
|
|
8c347d8764 | ||
|
|
f7bffdf63a | ||
|
|
bda43a4627 | ||
|
|
19195ddf96 | ||
|
|
a5935486ef | ||
|
|
ffd012906c | ||
|
|
f8a1fb2321 | ||
|
|
168b0f8df6 | ||
|
|
70d8378404 | ||
|
|
00e38ce126 | ||
|
|
02c3f8ed80 | ||
|
|
e949a458ec | ||
|
|
228ff3ba57 | ||
|
|
4c1dfd7eda | ||
|
|
e1799f1524 | ||
|
|
8f0e04027e | ||
|
|
abdafc8ee4 | ||
|
|
9030b559e8 | ||
|
|
cd34d02377 | ||
|
|
a362ef97df | ||
|
|
92f392d422 | ||
|
|
e8ddaab1c3 | ||
|
|
da78ff9151 | ||
|
|
e576c7a08e | ||
|
|
2d180cdacf | ||
|
|
77c7eb6fd9 | ||
|
|
857b5962da | ||
|
|
8c54c09ab7 | ||
|
|
6927a532cf | ||
|
|
49dccf4284 | ||
|
|
a4751ddd01 | ||
|
|
c811133aac | ||
|
|
c16ea42fad | ||
|
|
05e521ab03 | ||
|
|
1ef490feea | ||
|
|
3b826e41f6 | ||
|
|
d232299c77 | ||
|
|
f774d2aab1 | ||
|
|
642aed93d9 | ||
|
|
4f9c907248 | ||
|
|
612b2fe9d7 | ||
|
|
0fddf3e114 | ||
|
|
c3898e4abf | ||
|
|
726c09618a | ||
|
|
12f10ac414 | ||
|
|
77b3bf8bc2 | ||
|
|
a0e1d5f567 | ||
|
|
4e32c7edb3 | ||
|
|
c72def55fe | ||
|
|
982962ef0a | ||
|
|
90a470ed78 | ||
|
|
f812cac142 | ||
|
|
aeab3a709a | ||
|
|
7058f4eb63 | ||
|
|
8d51a20143 | ||
|
|
a4f6269724 | ||
|
|
fbfe57cd63 | ||
|
|
0118a78967 | ||
|
|
659c723ea3 | ||
|
|
bbb9a9cd1a | ||
|
|
5052a87a82 | ||
|
|
b9180a99d4 | ||
|
|
db1773d708 | ||
|
|
a1b009328d | ||
|
|
393a9ca4f2 | ||
|
|
e910a045d0 | ||
|
|
5d9a775699 | ||
|
|
8233143578 | ||
|
|
950cb8bc03 | ||
|
|
eafb04004e | ||
|
|
3d3e384d5c | ||
|
|
38533631bf | ||
|
|
6fe39ef065 | ||
|
|
47c3e14d4b | ||
|
|
d8b647cc3a | ||
|
|
abad4a3941 | ||
|
|
2c0a4914cf | ||
|
|
e54b49b442 | ||
|
|
50aa1e6baa | ||
|
|
e3c897fb68 | ||
|
|
728afc0587 | ||
|
|
95a9dc9db0 | ||
|
|
b62fef7541 | ||
|
|
dd490220d7 | ||
|
|
7f932b96ae | ||
|
|
4af9a20903 | ||
|
|
f9cb549fbe | ||
|
|
7e342e60d1 | ||
|
|
f98063d604 | ||
|
|
10c4fae8c0 | ||
|
|
cae24a226b | ||
|
|
0162322833 | ||
|
|
06dfe3c5ae | ||
|
|
a98c4038f4 | ||
|
|
4c760ec1b1 | ||
|
|
176d0bb7c0 | ||
|
|
bc90b857c9 | ||
|
|
ef0abf2b98 | ||
|
|
008a2969b2 | ||
|
|
7d9f9ba756 | ||
|
|
358b36bc66 | ||
|
|
f1e686f706 | ||
|
|
0b1fa54a4d | ||
|
|
24c7f47566 | ||
|
|
4037d707c9 | ||
|
|
001d4ab002 | ||
|
|
f115603093 | ||
|
|
d7bb284e57 | ||
|
|
11c53c26ff | ||
|
|
d28bbf4674 | ||
|
|
a7d662a7d8 | ||
|
|
6f8c464393 | ||
|
|
c8104a03e6 | ||
|
|
69559bcf4f | ||
|
|
d524821c86 | ||
|
|
e864244226 | ||
|
|
5074cf8beb | ||
|
|
b448de422e | ||
|
|
99d3571772 | ||
|
|
0354275b39 | ||
|
|
309fbc15b2 | ||
|
|
28e3c863bf | ||
|
|
06162290af | ||
|
|
628872d0e4 | ||
|
|
960523f45f | ||
|
|
fb04b17fad | ||
|
|
8adc831a31 | ||
|
|
566a99240d | ||
|
|
7b2241f051 | ||
|
|
55ed45f108 | ||
|
|
f8e7901b89 | ||
|
|
9e70e95242 | ||
|
|
68d38eff33 | ||
|
|
abd400801c | ||
|
|
d24a750ba4 | ||
|
|
9903eba7fb | ||
|
|
3752311f44 | ||
|
|
b71f771acb | ||
|
|
9f3145aec0 | ||
|
|
8638076ecb | ||
|
|
8649baccf7 | ||
|
|
c33d9e9668 | ||
|
|
03d70e1513 | ||
|
|
d20255b1b4 | ||
|
|
cd91e42a56 | ||
|
|
e2435be0b9 | ||
|
|
5adc188466 | ||
|
|
101ba0b796 | ||
|
|
8cd2012d27 | ||
|
|
4959596527 | ||
|
|
956c397c3c | ||
|
|
1249ede2b7 | ||
|
|
596ed330dd | ||
|
|
b4c1594d99 | ||
|
|
98cb08d853 | ||
|
|
6b86dcde4a | ||
|
|
fbeaab466a | ||
|
|
5e77b5da9f | ||
|
|
7c4225d01c | ||
|
|
ffa7be86fe | ||
|
|
c41c210ced | ||
|
|
de7d6c255c | ||
|
|
99060fbb64 | ||
|
|
0c8d648998 | ||
|
|
aa18d1985e | ||
|
|
b0edf924b4 | ||
|
|
997a46a90f | ||
|
|
b99b8f55f6 | ||
|
|
c0a50a2143 | ||
|
|
382734b057 | ||
|
|
90fbbea372 | ||
|
|
55d9ad0b55 | ||
|
|
e5e5d0d9e4 | ||
|
|
324b659d33 | ||
|
|
edcf899be1 | ||
|
|
2bf781d591 | ||
|
|
cc179c5270 | ||
|
|
b417725e3e | ||
|
|
c02d8225a8 | ||
|
|
659f570cfc | ||
|
|
c7e470bd5e | ||
|
|
fe4efa0e0e | ||
|
|
02234d00b7 | ||
|
|
bef5bfcbb6 | ||
|
|
290512ee68 | ||
|
|
d129d6eada | ||
|
|
5c5a3f2264 | ||
|
|
d4644a28c1 | ||
|
|
d66c70d1e6 | ||
|
|
b91e7a9860 | ||
|
|
fcdfda8ba2 | ||
|
|
2800fd919b | ||
|
|
512bbb99ca | ||
|
|
ed5b74b1ae | ||
|
|
791dff5a87 | ||
|
|
402cd8be19 | ||
|
|
bdcb1e3592 | ||
|
|
e60dd219dc | ||
|
|
9d7be5dcbf | ||
|
|
70e964d9f9 | ||
|
|
673a643184 | ||
|
|
2761872ea7 | ||
|
|
fc7195f19a | ||
|
|
8b8bb5e833 | ||
|
|
5d4f1bb3f1 | ||
|
|
139c3297ab | ||
|
|
20503de3ba | ||
|
|
2676892886 | ||
|
|
5acf5bf102 | ||
|
|
ec693008d7 | ||
|
|
4ba1846c11 | ||
|
|
5eceed81e1 | ||
|
|
8b725b4b8c | ||
|
|
6253c39100 | ||
|
|
b845013836 | ||
|
|
9690bc9c63 | ||
|
|
c6a8fe16c6 | ||
|
|
ec9a334f93 | ||
|
|
35d9de6b6e | ||
|
|
4d0df5d599 | ||
|
|
7fd082e941 | ||
|
|
9d17e0be9d | ||
|
|
030472d61c | ||
|
|
6bff52483b | ||
|
|
32d8ca2f21 | ||
|
|
fd6c8769dd | ||
|
|
bac6a47c67 | ||
|
|
18dd1c277b | ||
|
|
ab4c11c096 | ||
|
|
6bbea74a7d | ||
|
|
4f1efbe38f | ||
|
|
eeb5053919 | ||
|
|
d8a517f992 | ||
|
|
aa513d920e | ||
|
|
3327ed50a8 | ||
|
|
f31fcdae08 | ||
|
|
66b15b7076 | ||
|
|
c5a9f180af | ||
|
|
a9abf3ceb2 | ||
|
|
ed3b2716af | ||
|
|
69948cd09c | ||
|
|
f8c4b64782 | ||
|
|
a422647819 | ||
|
|
9262661135 | ||
|
|
01c4726fd5 | ||
|
|
0230362d33 | ||
|
|
f8669d4e95 | ||
|
|
12298f8953 | ||
|
|
daca8651f4 | ||
|
|
8039701f9e | ||
|
|
01f0bb3124 | ||
|
|
58a79773ee | ||
|
|
c832c0bf3f | ||
|
|
907364ce67 | ||
|
|
18cf7b046e | ||
|
|
87e5c38e32 | ||
|
|
c98972ab23 | ||
|
|
2a78ebabd9 | ||
|
|
a23a87a17f | ||
|
|
49b1acba43 | ||
|
|
464f6a6b08 | ||
|
|
7e7fac05e0 | ||
|
|
7296ce7287 | ||
|
|
70c8f7b1ee | ||
|
|
50b04d6b2b | ||
|
|
12056c8904 | ||
|
|
fdbda6f608 | ||
|
|
c822816f8e | ||
|
|
6d36c030e0 | ||
|
|
82c6be14f4 | ||
|
|
fb4ad043dd | ||
|
|
91ea039077 | ||
|
|
8e025db656 | ||
|
|
4e9293ba04 | ||
|
|
19afb57ac7 | ||
|
|
a032bbe087 | ||
|
|
a2943a6b7f | ||
|
|
8ad2b3c3d9 | ||
|
|
cd69e57a33 | ||
|
|
ca8a00f8a1 | ||
|
|
9077dea0cd | ||
|
|
d670257402 | ||
|
|
3460fb0d47 | ||
|
|
82eb7786d4 | ||
|
|
00385acc1d | ||
|
|
813940762c | ||
|
|
bd25d6db06 | ||
|
|
9fbc7aafb4 | ||
|
|
227819dc1e | ||
|
|
2c401f9041 | ||
|
|
c7e3a5cff4 | ||
|
|
5469df7dd1 | ||
|
|
071ddf6563 | ||
|
|
36b327b57b | ||
|
|
7587e6c08b | ||
|
|
c90d35869b | ||
|
|
67110ce739 | ||
|
|
5421d0d1c5 | ||
|
|
c458b4712a | ||
|
|
0200e3def5 | ||
|
|
6acc9a62f8 | ||
|
|
d6b2519843 | ||
|
|
c8046f4597 | ||
|
|
1c583ab487 | ||
|
|
936f84dfa6 | ||
|
|
491f080a37 | ||
|
|
8354bd91db | ||
|
|
fb1d5197fa | ||
|
|
cf321f7667 | ||
|
|
2d6b2e3811 | ||
|
|
d4dbfdbe91 | ||
|
|
c9a845d3aa | ||
|
|
1e41ca125d | ||
|
|
500ddd6585 | ||
|
|
9457df9ddd | ||
|
|
c3f23ddce8 | ||
|
|
8b308972a4 | ||
|
|
4f632c893c | ||
|
|
41066bd45e | ||
|
|
ac1048fcd7 | ||
|
|
14ea847ef6 | ||
|
|
2ce3a5f887 | ||
|
|
27858506ff | ||
|
|
6ba5c5d0e1 | ||
|
|
dc112a5a00 | ||
|
|
fe60ffb6ff | ||
|
|
512270593b | ||
|
|
2cd6347a13 | ||
|
|
b1f66b181c | ||
|
|
d5dae844bd | ||
|
|
e0a8e993bc | ||
|
|
1aff04faab | ||
|
|
295c0861c4 | ||
|
|
ba3f73acb8 | ||
|
|
68959582b9 | ||
|
|
1f9b563412 | ||
|
|
99bc46b8b8 | ||
|
|
e2d2af3afa | ||
|
|
af4c4d4f1f | ||
|
|
6d06bfb452 | ||
|
|
159a1a4645 | ||
|
|
d4b230c137 | ||
|
|
6f501119bf | ||
|
|
a00df0da90 | ||
|
|
6d90f12bb6 | ||
|
|
469eef8231 | ||
|
|
1ccad22227 | ||
|
|
5cf76ba8b3 | ||
|
|
81bc8471e3 | ||
|
|
5feea2e0f8 | ||
|
|
79b35c59a5 | ||
|
|
35749f0330 | ||
|
|
2889efb608 | ||
|
|
686c543778 | ||
|
|
093dc907b3 | ||
|
|
1144049c66 | ||
|
|
6e11ff3796 | ||
|
|
19013b09e0 | ||
|
|
7539d88f54 | ||
|
|
28f895cec2 | ||
|
|
751bc45bef | ||
|
|
ae83ca6893 | ||
|
|
5f4efedbdd | ||
|
|
9d49c6861f | ||
|
|
3b56288a5e | ||
|
|
f257f4febb | ||
|
|
df867f3349 | ||
|
|
5270c20263 | ||
|
|
7762cd0a68 | ||
|
|
e91cc9cd08 | ||
|
|
741825a04e | ||
|
|
49b27da426 | ||
|
|
bf4bbd15e5 | ||
|
|
baa69c3c81 | ||
|
|
ac644605f2 | ||
|
|
94da339622 | ||
|
|
366359803a | ||
|
|
3b13397165 | ||
|
|
163c2b2544 | ||
|
|
9e2603c1bf | ||
|
|
d27750590a | ||
|
|
33a00ab9e5 | ||
|
|
f765fe36d7 | ||
|
|
be7a95c9a5 | ||
|
|
2571480bb6 | ||
|
|
73d928751d | ||
|
|
0c19544d94 | ||
|
|
a80dce2e3b | ||
|
|
fb09d1ad2b | ||
|
|
963e4dd2fc | ||
|
|
a5d81c6cc9 | ||
|
|
b167e73acb | ||
|
|
e7af464033 | ||
|
|
28e454fd4a | ||
|
|
55a9c9ae0a | ||
|
|
b3eef76cdd | ||
|
|
3f81ff3507 | ||
|
|
2347ba6f39 | ||
|
|
b9d3c26eae | ||
|
|
cd6670205c | ||
|
|
9f4ac4f4f3 | ||
|
|
e4bed4d963 | ||
|
|
76b5c8b145 | ||
|
|
9836c45e03 | ||
|
|
51f1712564 | ||
|
|
e9eff8be5c | ||
|
|
4855045ea2 | ||
|
|
6b06ae528c | ||
|
|
813961b458 | ||
|
|
7ae9d26cd1 | ||
|
|
9e5cc7c910 | ||
|
|
7d166fd730 | ||
|
|
60101fd97b | ||
|
|
0bc174697a | ||
|
|
7bee5b3abc | ||
|
|
656b285195 | ||
|
|
86083531c6 | ||
|
|
c01f70105f | ||
|
|
5aafa91e22 | ||
|
|
bada564c10 | ||
|
|
f9f0d86ddf | ||
|
|
6beabb5e8a | ||
|
|
3719938849 | ||
|
|
6420990007 | ||
|
|
1fab24b9bc | ||
|
|
8bbe63bd9d | ||
|
|
fa3b1552cf | ||
|
|
c625b30781 | ||
|
|
b339750757 | ||
|
|
da960a9de4 | ||
|
|
ce30162907 | ||
|
|
c0cdcbb9e0 | ||
|
|
954a20ff4c | ||
|
|
8057b994cf | ||
|
|
ea111b058e | ||
|
|
ce33074626 | ||
|
|
5f95a92135 | ||
|
|
cd817906b2 | ||
|
|
29dbc26dbd | ||
|
|
04f0130530 | ||
|
|
f210a6e91a | ||
|
|
aded0706be | ||
|
|
57567db017 | ||
|
|
5574e4f11b | ||
|
|
4b01b666f6 | ||
|
|
35740895ed | ||
|
|
4c5d84d106 | ||
|
|
a8915f0331 | ||
|
|
7f962e19c2 | ||
|
|
186fd4da74 | ||
|
|
2fdcf5347b | ||
|
|
4a983995a8 | ||
|
|
263bdc9687 | ||
|
|
42c76aaebc | ||
|
|
9326cb5411 | ||
|
|
415b69155b | ||
|
|
3423d29815 | ||
|
|
673a972fe9 | ||
|
|
1fd20b636b | ||
|
|
d7a2556292 | ||
|
|
8aa158d4e6 | ||
|
|
3595b1f8e9 | ||
|
|
9b867a221a | ||
|
|
46a016cdce | ||
|
|
bea9cd2fe2 | ||
|
|
ee9d9a52a9 | ||
|
|
1e8a875edb | ||
|
|
36a93c90eb | ||
|
|
38d714a28a | ||
|
|
bbb954afc5 | ||
|
|
de5d16eeac | ||
|
|
1968195da9 | ||
|
|
22851df145 | ||
|
|
96ade5f2dd | ||
|
|
5e727819ad | ||
|
|
5605aae269 | ||
|
|
21415a9847 | ||
|
|
8c05251cce | ||
|
|
7c15d1e8c3 |
+6
-29
@@ -1,6 +1,6 @@
|
|||||||
version: 2.1
|
version: 2.1
|
||||||
orbs:
|
orbs:
|
||||||
go: gotest/tools@0.0.9
|
go: gotest/tools@0.0.13
|
||||||
|
|
||||||
executors:
|
executors:
|
||||||
golang:
|
golang:
|
||||||
@@ -45,7 +45,7 @@ commands:
|
|||||||
- 'v25-2k-lotus-params'
|
- 'v25-2k-lotus-params'
|
||||||
paths:
|
paths:
|
||||||
- /var/tmp/filecoin-proof-parameters/
|
- /var/tmp/filecoin-proof-parameters/
|
||||||
- run: ./lotus fetch-params --proving-params 2048
|
- run: ./lotus fetch-params 2048
|
||||||
- save_cache:
|
- save_cache:
|
||||||
name: Save parameters cache
|
name: Save parameters cache
|
||||||
key: 'v25-2k-lotus-params'
|
key: 'v25-2k-lotus-params'
|
||||||
@@ -79,7 +79,6 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- install-deps
|
- install-deps
|
||||||
- prepare
|
- prepare
|
||||||
- go/mod-download
|
|
||||||
- go/mod-tidy-check
|
- go/mod-tidy-check
|
||||||
|
|
||||||
build-all:
|
build-all:
|
||||||
@@ -87,12 +86,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- install-deps
|
- install-deps
|
||||||
- prepare
|
- prepare
|
||||||
- go/mod-download
|
|
||||||
- run: sudo apt-get update
|
- run: sudo apt-get update
|
||||||
- run: sudo apt-get install npm
|
- run: sudo apt-get install npm
|
||||||
- restore_cache:
|
|
||||||
name: restore go mod cache
|
|
||||||
key: v1-go-deps-{{ arch }}-{{ checksum "/home/circleci/project/go.mod" }}
|
|
||||||
- run:
|
- run:
|
||||||
command: make buildall
|
command: make buildall
|
||||||
- store_artifacts:
|
- store_artifacts:
|
||||||
@@ -112,10 +107,6 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- install-deps
|
- install-deps
|
||||||
- prepare
|
- prepare
|
||||||
- go/mod-download
|
|
||||||
- restore_cache:
|
|
||||||
name: restore go mod cache
|
|
||||||
key: v1-go-deps-{{ arch }}-{{ checksum "/home/circleci/project/go.mod" }}
|
|
||||||
- run:
|
- run:
|
||||||
command: make debug
|
command: make debug
|
||||||
|
|
||||||
@@ -159,10 +150,6 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- install-deps
|
- install-deps
|
||||||
- prepare
|
- prepare
|
||||||
- go/mod-download
|
|
||||||
- restore_cache:
|
|
||||||
name: restore go mod cache
|
|
||||||
key: v1-go-deps-{{ arch }}-{{ checksum "/home/circleci/project/go.mod" }}
|
|
||||||
- run:
|
- run:
|
||||||
command: make deps lotus
|
command: make deps lotus
|
||||||
no_output_timeout: 30m
|
no_output_timeout: 30m
|
||||||
@@ -193,13 +180,6 @@ jobs:
|
|||||||
shell: /bin/bash -eo pipefail
|
shell: /bin/bash -eo pipefail
|
||||||
command: |
|
command: |
|
||||||
bash <(curl -s https://codecov.io/bash)
|
bash <(curl -s https://codecov.io/bash)
|
||||||
- save_cache:
|
|
||||||
name: save go mod cache
|
|
||||||
key: v1-go-deps-{{ arch }}-{{ checksum "/home/circleci/project/go.mod" }}
|
|
||||||
paths:
|
|
||||||
- "~/go/pkg"
|
|
||||||
- "~/go/src/github.com"
|
|
||||||
- "~/go/src/golang.org"
|
|
||||||
|
|
||||||
test-short:
|
test-short:
|
||||||
<<: *test
|
<<: *test
|
||||||
@@ -234,10 +214,9 @@ jobs:
|
|||||||
curl --location https://github.com/stedolan/jq/releases/download/jq-1.6/jq-osx-amd64 --output /usr/local/bin/jq
|
curl --location https://github.com/stedolan/jq/releases/download/jq-1.6/jq-osx-amd64 --output /usr/local/bin/jq
|
||||||
chmod +x /usr/local/bin/jq
|
chmod +x /usr/local/bin/jq
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
name: restore go mod and cargo cache
|
name: restore cargo cache
|
||||||
key: v3-go-deps-{{ arch }}-{{ checksum "~/go/src/github.com/filecoin-project/lotus/go.sum" }}
|
key: v3-go-deps-{{ arch }}-{{ checksum "~/go/src/github.com/filecoin-project/lotus/go.sum" }}
|
||||||
- install-deps
|
- install-deps
|
||||||
- go/mod-download
|
|
||||||
- run:
|
- run:
|
||||||
command: make build
|
command: make build
|
||||||
no_output_timeout: 30m
|
no_output_timeout: 30m
|
||||||
@@ -264,7 +243,6 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- install-deps
|
- install-deps
|
||||||
- prepare
|
- prepare
|
||||||
- go/mod-download
|
|
||||||
- run:
|
- run:
|
||||||
command: "! go fmt ./... 2>&1 | read"
|
command: "! go fmt ./... 2>&1 | read"
|
||||||
|
|
||||||
@@ -277,7 +255,7 @@ jobs:
|
|||||||
default: golang
|
default: golang
|
||||||
golangci-lint-version:
|
golangci-lint-version:
|
||||||
type: string
|
type: string
|
||||||
default: 1.23.8
|
default: 1.27.0
|
||||||
concurrency:
|
concurrency:
|
||||||
type: string
|
type: string
|
||||||
default: '2'
|
default: '2'
|
||||||
@@ -293,7 +271,6 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- install-deps
|
- install-deps
|
||||||
- prepare
|
- prepare
|
||||||
- go/mod-download
|
|
||||||
- run:
|
- run:
|
||||||
command: make deps
|
command: make deps
|
||||||
no_output_timeout: 30m
|
no_output_timeout: 30m
|
||||||
@@ -303,7 +280,7 @@ jobs:
|
|||||||
- run:
|
- run:
|
||||||
name: Lint
|
name: Lint
|
||||||
command: |
|
command: |
|
||||||
$HOME/.local/bin/golangci-lint run -v \
|
$HOME/.local/bin/golangci-lint run -v --timeout 2m \
|
||||||
--concurrency << parameters.concurrency >> << parameters.args >>
|
--concurrency << parameters.concurrency >> << parameters.args >>
|
||||||
lint-changes:
|
lint-changes:
|
||||||
<<: *lint
|
<<: *lint
|
||||||
@@ -337,7 +314,7 @@ workflows:
|
|||||||
ci:
|
ci:
|
||||||
jobs:
|
jobs:
|
||||||
- lint-changes:
|
- lint-changes:
|
||||||
args: "--new-from-rev origin/next"
|
args: "--new-from-rev origin/master"
|
||||||
- mod-tidy-check
|
- mod-tidy-check
|
||||||
- gofmt
|
- gofmt
|
||||||
- test:
|
- test:
|
||||||
|
|||||||
@@ -35,3 +35,4 @@ build/paramfetch.sh
|
|||||||
bin/ipget
|
bin/ipget
|
||||||
bin/tmp/*
|
bin/tmp/*
|
||||||
.idea
|
.idea
|
||||||
|
scratchpad
|
||||||
|
|||||||
@@ -37,6 +37,10 @@ issues:
|
|||||||
- path: build/params_.*\.go
|
- path: build/params_.*\.go
|
||||||
linters:
|
linters:
|
||||||
- golint
|
- golint
|
||||||
|
|
||||||
|
- path: api/apistruct/struct.go
|
||||||
|
linters:
|
||||||
|
- golint
|
||||||
|
|
||||||
- path: .*_test.go
|
- path: .*_test.go
|
||||||
linters:
|
linters:
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ all: build
|
|||||||
unexport GOFLAGS
|
unexport GOFLAGS
|
||||||
|
|
||||||
GOVERSION:=$(shell go version | cut -d' ' -f 3 | cut -d. -f 2)
|
GOVERSION:=$(shell go version | cut -d' ' -f 3 | cut -d. -f 2)
|
||||||
ifeq ($(shell expr $(GOVERSION) \< 13), 1)
|
ifeq ($(shell expr $(GOVERSION) \< 14), 1)
|
||||||
$(warning Your Golang version is go 1.$(GOVERSION))
|
$(warning Your Golang version is go 1.$(GOVERSION))
|
||||||
$(error Update Golang to version $(shell grep '^go' go.mod))
|
$(error Update Golang to version $(shell grep '^go' go.mod))
|
||||||
endif
|
endif
|
||||||
@@ -105,15 +105,17 @@ install:
|
|||||||
|
|
||||||
install-services: install
|
install-services: install
|
||||||
mkdir -p /usr/local/lib/systemd/system
|
mkdir -p /usr/local/lib/systemd/system
|
||||||
|
mkdir -p /var/log/lotus
|
||||||
install -C -m 0644 ./scripts/lotus-daemon.service /usr/local/lib/systemd/system/lotus-daemon.service
|
install -C -m 0644 ./scripts/lotus-daemon.service /usr/local/lib/systemd/system/lotus-daemon.service
|
||||||
install -C -m 0644 ./scripts/lotus-miner.service /usr/local/lib/systemd/system/lotus-miner.service
|
install -C -m 0644 ./scripts/lotus-miner.service /usr/local/lib/systemd/system/lotus-miner.service
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
@echo
|
@echo
|
||||||
@echo "lotus and lotus-miner services installed. Don't forget to 'systemctl enable lotus|lotus-miner' for it to be enabled on startup."
|
@echo "lotus-daemon and lotus-miner services installed. Don't forget to 'systemctl enable lotus-daemon|lotus-miner' for it to be enabled on startup."
|
||||||
|
|
||||||
clean-services:
|
clean-services:
|
||||||
rm -f /usr/local/lib/systemd/system/lotus-daemon.service
|
rm -f /usr/local/lib/systemd/system/lotus-daemon.service
|
||||||
rm -f /usr/local/lib/systemd/system/lotus-miner.service
|
rm -f /usr/local/lib/systemd/system/lotus-miner.service
|
||||||
|
rm -f /usr/local/lib/systemd/system/chainwatch.service
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
|
|
||||||
# TOOLS
|
# TOOLS
|
||||||
@@ -160,6 +162,13 @@ chainwatch:
|
|||||||
.PHONY: chainwatch
|
.PHONY: chainwatch
|
||||||
BINS+=chainwatch
|
BINS+=chainwatch
|
||||||
|
|
||||||
|
install-chainwatch-service: chainwatch
|
||||||
|
install -C ./chainwatch /usr/local/bin/chainwatch
|
||||||
|
install -C -m 0644 ./scripts/chainwatch.service /usr/local/lib/systemd/system/chainwatch.service
|
||||||
|
systemctl daemon-reload
|
||||||
|
@echo
|
||||||
|
@echo "chainwatch installed. Don't forget to 'systemctl enable chainwatch' for it to be enabled on startup."
|
||||||
|
|
||||||
bench:
|
bench:
|
||||||
rm -f bench
|
rm -f bench
|
||||||
go build -o bench ./cmd/lotus-bench
|
go build -o bench ./cmd/lotus-bench
|
||||||
@@ -182,6 +191,12 @@ health:
|
|||||||
.PHONY: health
|
.PHONY: health
|
||||||
BINS+=health
|
BINS+=health
|
||||||
|
|
||||||
|
testground:
|
||||||
|
go build -tags testground -o /dev/null ./cmd/lotus
|
||||||
|
|
||||||
|
.PHONY: testground
|
||||||
|
BINS+=testground
|
||||||
|
|
||||||
# MISC
|
# MISC
|
||||||
|
|
||||||
buildall: $(BINS)
|
buildall: $(BINS)
|
||||||
|
|||||||
@@ -4,14 +4,23 @@
|
|||||||
|
|
||||||
Lotus is an implementation of the Filecoin Distributed Storage Network. For more details about Filecoin, check out the [Filecoin Spec](https://github.com/filecoin-project/specs).
|
Lotus is an implementation of the Filecoin Distributed Storage Network. For more details about Filecoin, check out the [Filecoin Spec](https://github.com/filecoin-project/specs).
|
||||||
|
|
||||||
## Development
|
|
||||||
|
|
||||||
All work is tracked via issues. An attempt at keeping an up-to-date view on remaining work is in the [lotus testnet github project board](https://github.com/filecoin-project/lotus/projects/1).
|
|
||||||
|
|
||||||
## Building & Documentation
|
## 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://docs.lotu.sh](https://docs.lotu.sh) or read the source [here](https://github.com/filecoin-project/lotus/tree/master/documentation).
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
Please send an email to security@filecoin.org. See our [security policy](SECURITY.md) for more details.
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
All work is tracked via issues. An attempt at keeping an up-to-date view on remaining work is in the [lotus testnet github project board](https://github.com/filecoin-project/lotus/projects/1).
|
||||||
|
|
||||||
|
The main branches under development at the moment are:
|
||||||
|
* [`master`](https://github.com/filecoin-project/lotus): current testnet.
|
||||||
|
* [`next`](https://github.com/filecoin-project/lotus/tree/next): working branch with chain-breaking changes.
|
||||||
|
* [`interopnet`](https://github.com/filecoin-project/lotus/tree/interopnet): devnet running one of `next` commits.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Dual-licensed under [MIT](https://github.com/filecoin-project/lotus/blob/master/LICENSE-MIT) + [Apache 2.0](https://github.com/filecoin-project/lotus/blob/master/LICENSE-APACHE)
|
Dual-licensed under [MIT](https://github.com/filecoin-project/lotus/blob/master/LICENSE-MIT) + [Apache 2.0](https://github.com/filecoin-project/lotus/blob/master/LICENSE-APACHE)
|
||||||
|
|||||||
+29
@@ -0,0 +1,29 @@
|
|||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
For *critical* bugs, please send an email to security@filecoin.org.
|
||||||
|
|
||||||
|
The bug reporting process differs between bugs that are critical and may crash the network, and others that are unlikely to cause problems if malicious parties know about it. For non-critical bugs, please simply file a GitHub [issue](https://github.com/filecoin-project/lotus/issues/new?template=bug_report.md).
|
||||||
|
|
||||||
|
Please try to provide a clear description of any bugs reported, along with how to reproduce the bug if possible. More detailed bug reports (especially those with a PoC included) will help us move forward much faster. Additionally, please avoid reporting bugs that already have open issues. Take a moment to search the issue list of the related GitHub repositories before writing up a new report.
|
||||||
|
|
||||||
|
Here are some examples of bugs we would consider 'critical':
|
||||||
|
|
||||||
|
* If you can spend from a `multisig` wallet you do not control the keys for.
|
||||||
|
* If you can cause a miner to be slashed without them actually misbehaving.
|
||||||
|
* If you can maintain power without submitting windowed posts regularly.
|
||||||
|
* If you can craft a message that causes lotus nodes to panic.
|
||||||
|
* If you can cause your miner to win significantly more blocks than it should.
|
||||||
|
* If you can craft a message that causes a persistent fork in the network.
|
||||||
|
* If you can cause the total amount of Filecoin in the network to no longer be 2 billion.
|
||||||
|
|
||||||
|
This is not an exhaustive list, but should provide some idea of what we consider 'critical'.
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
|
||||||
|
* TODO: This should be defined and set up by Mainnet launch.
|
||||||
|
|
||||||
|
| Version | Supported |
|
||||||
|
| ------- | ------------------ |
|
||||||
|
| Testnet | :white_check_mark: |
|
||||||
+12
-2
@@ -13,11 +13,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Common interface {
|
type Common interface {
|
||||||
// Auth
|
|
||||||
|
// MethodGroup: Auth
|
||||||
|
|
||||||
AuthVerify(ctx context.Context, token string) ([]auth.Permission, error)
|
AuthVerify(ctx context.Context, token string) ([]auth.Permission, error)
|
||||||
AuthNew(ctx context.Context, perms []auth.Permission) ([]byte, error)
|
AuthNew(ctx context.Context, perms []auth.Permission) ([]byte, error)
|
||||||
|
|
||||||
// network
|
// MethodGroup: Net
|
||||||
|
|
||||||
NetConnectedness(context.Context, peer.ID) (network.Connectedness, error)
|
NetConnectedness(context.Context, peer.ID) (network.Connectedness, error)
|
||||||
NetPeers(context.Context) ([]peer.AddrInfo, error)
|
NetPeers(context.Context) ([]peer.AddrInfo, error)
|
||||||
@@ -25,6 +27,9 @@ type Common interface {
|
|||||||
NetAddrsListen(context.Context) (peer.AddrInfo, error)
|
NetAddrsListen(context.Context) (peer.AddrInfo, error)
|
||||||
NetDisconnect(context.Context, peer.ID) error
|
NetDisconnect(context.Context, peer.ID) error
|
||||||
NetFindPeer(context.Context, peer.ID) (peer.AddrInfo, error)
|
NetFindPeer(context.Context, peer.ID) (peer.AddrInfo, error)
|
||||||
|
NetPubsubScores(context.Context) ([]PubsubScore, error)
|
||||||
|
|
||||||
|
// MethodGroup: Common
|
||||||
|
|
||||||
// ID returns peerID of libp2p node backing this API
|
// ID returns peerID of libp2p node backing this API
|
||||||
ID(context.Context) (peer.ID, error)
|
ID(context.Context) (peer.ID, error)
|
||||||
@@ -34,6 +39,11 @@ type Common interface {
|
|||||||
|
|
||||||
LogList(context.Context) ([]string, error)
|
LogList(context.Context) ([]string, error)
|
||||||
LogSetLevel(context.Context, string, string) error
|
LogSetLevel(context.Context, string, string) error
|
||||||
|
|
||||||
|
// trigger graceful shutdown
|
||||||
|
Shutdown(context.Context) error
|
||||||
|
|
||||||
|
Closing(context.Context) (<-chan struct{}, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Version provides various build-time information
|
// Version provides various build-time information
|
||||||
|
|||||||
+82
-13
@@ -35,26 +35,71 @@ type FullNode interface {
|
|||||||
// ChainNotify returns channel with chain head updates
|
// ChainNotify returns channel with chain head updates
|
||||||
// First message is guaranteed to be of len == 1, and type == 'current'
|
// First message is guaranteed to be of len == 1, and type == 'current'
|
||||||
ChainNotify(context.Context) (<-chan []*HeadChange, error)
|
ChainNotify(context.Context) (<-chan []*HeadChange, error)
|
||||||
|
|
||||||
// ChainHead returns the current head of the chain
|
// ChainHead returns the current head of the chain
|
||||||
ChainHead(context.Context) (*types.TipSet, error)
|
ChainHead(context.Context) (*types.TipSet, error)
|
||||||
|
|
||||||
// ChainGetRandomness is used to sample the chain for randomness
|
// ChainGetRandomness is used to sample the chain for randomness
|
||||||
ChainGetRandomness(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error)
|
ChainGetRandomness(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error)
|
||||||
|
|
||||||
// ChainGetBlock returns the block specified by the given CID
|
// ChainGetBlock returns the block specified by the given CID
|
||||||
ChainGetBlock(context.Context, cid.Cid) (*types.BlockHeader, error)
|
ChainGetBlock(context.Context, cid.Cid) (*types.BlockHeader, error)
|
||||||
ChainGetTipSet(context.Context, types.TipSetKey) (*types.TipSet, error)
|
ChainGetTipSet(context.Context, types.TipSetKey) (*types.TipSet, error)
|
||||||
ChainGetBlockMessages(context.Context, cid.Cid) (*BlockMessages, error)
|
|
||||||
ChainGetParentReceipts(context.Context, cid.Cid) ([]*types.MessageReceipt, error)
|
// ChainGetBlockMessages returns messages stored in the specified block
|
||||||
ChainGetParentMessages(context.Context, cid.Cid) ([]Message, error)
|
ChainGetBlockMessages(ctx context.Context, blockCid cid.Cid) (*BlockMessages, error)
|
||||||
|
|
||||||
|
// ChainGetParentReceipts returns receipts for messages in parent tipset of
|
||||||
|
// the specified block
|
||||||
|
ChainGetParentReceipts(ctx context.Context, blockCid cid.Cid) ([]*types.MessageReceipt, error)
|
||||||
|
|
||||||
|
// ChainGetParentReceipts returns messages stored in parent tipset of the
|
||||||
|
// specified block
|
||||||
|
ChainGetParentMessages(ctx context.Context, blockCid cid.Cid) ([]Message, error)
|
||||||
|
|
||||||
|
// ChainGetTipSetByHeight looks back for a tipset at the specified epoch.
|
||||||
|
// If there are no blocks at the specified epoch, a tipset at higher epoch
|
||||||
|
// will be returned
|
||||||
ChainGetTipSetByHeight(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error)
|
ChainGetTipSetByHeight(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error)
|
||||||
|
|
||||||
|
// ChainReadObj reads ipld nodes referenced by the specified CID from chain
|
||||||
|
// blockstore and returns raw bytes
|
||||||
ChainReadObj(context.Context, cid.Cid) ([]byte, error)
|
ChainReadObj(context.Context, cid.Cid) ([]byte, error)
|
||||||
|
|
||||||
|
// ChainHasObj checks if a given CID exists in the chain blockstore
|
||||||
ChainHasObj(context.Context, cid.Cid) (bool, error)
|
ChainHasObj(context.Context, cid.Cid) (bool, error)
|
||||||
ChainStatObj(context.Context, cid.Cid, cid.Cid) (ObjStat, error)
|
ChainStatObj(context.Context, cid.Cid, cid.Cid) (ObjStat, error)
|
||||||
|
|
||||||
|
// ChainSetHead forcefully sets current chain head. Use with caution
|
||||||
ChainSetHead(context.Context, types.TipSetKey) error
|
ChainSetHead(context.Context, types.TipSetKey) error
|
||||||
|
|
||||||
|
// ChainGetGenesis returns the genesis tipset
|
||||||
ChainGetGenesis(context.Context) (*types.TipSet, error)
|
ChainGetGenesis(context.Context) (*types.TipSet, error)
|
||||||
|
|
||||||
|
// ChainTipSetWeight computes weight for the specified tipset
|
||||||
ChainTipSetWeight(context.Context, types.TipSetKey) (types.BigInt, error)
|
ChainTipSetWeight(context.Context, types.TipSetKey) (types.BigInt, error)
|
||||||
ChainGetNode(ctx context.Context, p string) (*IpldObject, error)
|
ChainGetNode(ctx context.Context, p string) (*IpldObject, error)
|
||||||
|
|
||||||
|
// ChainGetMessage reads a message referenced by the specified CID from the
|
||||||
|
// chain blockstore
|
||||||
ChainGetMessage(context.Context, cid.Cid) (*types.Message, error)
|
ChainGetMessage(context.Context, cid.Cid) (*types.Message, error)
|
||||||
|
|
||||||
|
// ChainGetPath returns a set of revert/apply operations needed to get from
|
||||||
|
// one tipset to another, for example:
|
||||||
|
//```
|
||||||
|
// to
|
||||||
|
// ^
|
||||||
|
// from tAA
|
||||||
|
// ^ ^
|
||||||
|
// tBA tAB
|
||||||
|
// ^---*--^
|
||||||
|
// ^
|
||||||
|
// tRR
|
||||||
|
//```
|
||||||
|
// Would return `[revert(tBA), apply(tAB), apply(tAA)]`
|
||||||
ChainGetPath(ctx context.Context, from types.TipSetKey, to types.TipSetKey) ([]*HeadChange, error)
|
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)
|
ChainExport(context.Context, types.TipSetKey) (<-chan []byte, error)
|
||||||
|
|
||||||
// MethodGroup: Sync
|
// MethodGroup: Sync
|
||||||
@@ -63,23 +108,45 @@ type FullNode interface {
|
|||||||
|
|
||||||
// SyncState returns the current status of the lotus sync system
|
// SyncState returns the current status of the lotus sync system
|
||||||
SyncState(context.Context) (*SyncState, error)
|
SyncState(context.Context) (*SyncState, error)
|
||||||
|
|
||||||
// SyncSubmitBlock can be used to submit a newly created block to the
|
// SyncSubmitBlock can be used to submit a newly created block to the
|
||||||
// network through this node
|
// network through this node
|
||||||
SyncSubmitBlock(ctx context.Context, blk *types.BlockMsg) error
|
SyncSubmitBlock(ctx context.Context, blk *types.BlockMsg) error
|
||||||
|
|
||||||
|
// SyncIncomingBlocks returns a channel streaming incoming, potentially not
|
||||||
|
// yet synced block headers.
|
||||||
SyncIncomingBlocks(ctx context.Context) (<-chan *types.BlockHeader, error)
|
SyncIncomingBlocks(ctx context.Context) (<-chan *types.BlockHeader, error)
|
||||||
|
|
||||||
|
// SyncMarkBad marks a blocks as bad, meaning that it won't ever by synced.
|
||||||
|
// Use with extreme caution
|
||||||
SyncMarkBad(ctx context.Context, bcid cid.Cid) error
|
SyncMarkBad(ctx context.Context, bcid cid.Cid) error
|
||||||
|
|
||||||
|
// SyncCheckBad checks if a block was marked as bad, and if it was, returns
|
||||||
|
// the reason
|
||||||
SyncCheckBad(ctx context.Context, bcid cid.Cid) (string, error)
|
SyncCheckBad(ctx context.Context, bcid cid.Cid) (string, error)
|
||||||
|
|
||||||
// MethodGroup: Mpool
|
// MethodGroup: Mpool
|
||||||
// The Mpool methods are for interacting with the message pool. The message pool
|
// The Mpool methods are for interacting with the message pool. The message pool
|
||||||
// manages all incoming and outgoing 'messages' going over the network.
|
// manages all incoming and outgoing 'messages' going over the network.
|
||||||
|
|
||||||
|
// MpoolPending returns pending mempool messages
|
||||||
MpoolPending(context.Context, types.TipSetKey) ([]*types.SignedMessage, error)
|
MpoolPending(context.Context, types.TipSetKey) ([]*types.SignedMessage, error)
|
||||||
|
|
||||||
|
// MpoolPush pushes a signed message to mempool
|
||||||
MpoolPush(context.Context, *types.SignedMessage) (cid.Cid, error)
|
MpoolPush(context.Context, *types.SignedMessage) (cid.Cid, error)
|
||||||
MpoolPushMessage(context.Context, *types.Message) (*types.SignedMessage, error) // get nonce, sign, push
|
|
||||||
|
// MpoolPushMessage atomically assigns a nonce, signs, and pushes a message
|
||||||
|
// to mempool
|
||||||
|
MpoolPushMessage(context.Context, *types.Message) (*types.SignedMessage, error)
|
||||||
|
|
||||||
|
// MpoolGetNonce gets next nonce for the specified sender.
|
||||||
|
// Note that this method may not be atomic. Use MpoolPushMessage instead
|
||||||
MpoolGetNonce(context.Context, address.Address) (uint64, error)
|
MpoolGetNonce(context.Context, address.Address) (uint64, error)
|
||||||
MpoolSub(context.Context) (<-chan MpoolUpdate, error)
|
MpoolSub(context.Context) (<-chan MpoolUpdate, error)
|
||||||
MpoolEstimateGasPrice(context.Context, uint64, address.Address, int64, types.TipSetKey) (types.BigInt, error)
|
|
||||||
|
// MpoolEstimateGasPrice estimates what gas price should be used for a
|
||||||
|
// message to have high likelihood of inclusion in `nblocksincl` epochs
|
||||||
|
MpoolEstimateGasPrice(ctx context.Context, nblocksincl uint64, sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error)
|
||||||
|
|
||||||
// MethodGroup: Miner
|
// MethodGroup: Miner
|
||||||
|
|
||||||
@@ -101,6 +168,7 @@ type FullNode interface {
|
|||||||
WalletSetDefault(context.Context, address.Address) error
|
WalletSetDefault(context.Context, address.Address) error
|
||||||
WalletExport(context.Context, address.Address) (*types.KeyInfo, error)
|
WalletExport(context.Context, address.Address) (*types.KeyInfo, error)
|
||||||
WalletImport(context.Context, *types.KeyInfo) (address.Address, error)
|
WalletImport(context.Context, *types.KeyInfo) (address.Address, error)
|
||||||
|
WalletDelete(context.Context, address.Address) error
|
||||||
|
|
||||||
// Other
|
// Other
|
||||||
|
|
||||||
@@ -117,6 +185,7 @@ type FullNode interface {
|
|||||||
ClientListDeals(ctx context.Context) ([]DealInfo, error)
|
ClientListDeals(ctx context.Context) ([]DealInfo, error)
|
||||||
ClientHasLocal(ctx context.Context, root cid.Cid) (bool, error)
|
ClientHasLocal(ctx context.Context, root cid.Cid) (bool, error)
|
||||||
ClientFindData(ctx context.Context, root cid.Cid) ([]QueryOffer, error)
|
ClientFindData(ctx context.Context, root cid.Cid) ([]QueryOffer, error)
|
||||||
|
ClientMinerQueryOffer(ctx context.Context, root cid.Cid, miner address.Address) (QueryOffer, error)
|
||||||
ClientRetrieve(ctx context.Context, order RetrievalOrder, ref *FileRef) error
|
ClientRetrieve(ctx context.Context, order RetrievalOrder, ref *FileRef) error
|
||||||
ClientQueryAsk(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.SignedStorageAsk, error)
|
ClientQueryAsk(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.SignedStorageAsk, error)
|
||||||
ClientCalcCommP(ctx context.Context, inpath string, miner address.Address) (*CommPRet, error)
|
ClientCalcCommP(ctx context.Context, inpath string, miner address.Address) (*CommPRet, error)
|
||||||
@@ -137,7 +206,7 @@ type FullNode interface {
|
|||||||
StateCall(context.Context, *types.Message, types.TipSetKey) (*InvocResult, error)
|
StateCall(context.Context, *types.Message, types.TipSetKey) (*InvocResult, error)
|
||||||
StateReplay(context.Context, types.TipSetKey, cid.Cid) (*InvocResult, error)
|
StateReplay(context.Context, types.TipSetKey, cid.Cid) (*InvocResult, error)
|
||||||
StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error)
|
StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error)
|
||||||
StateReadState(ctx context.Context, act *types.Actor, tsk types.TipSetKey) (*ActorState, error)
|
StateReadState(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*ActorState, error)
|
||||||
StateListMessages(ctx context.Context, match *types.Message, tsk types.TipSetKey, toht abi.ChainEpoch) ([]cid.Cid, error)
|
StateListMessages(ctx context.Context, match *types.Message, tsk types.TipSetKey, toht abi.ChainEpoch) ([]cid.Cid, error)
|
||||||
|
|
||||||
StateNetworkName(context.Context) (dtypes.NetworkName, error)
|
StateNetworkName(context.Context) (dtypes.NetworkName, error)
|
||||||
@@ -145,7 +214,7 @@ type FullNode interface {
|
|||||||
StateMinerProvingSet(context.Context, address.Address, types.TipSetKey) ([]*ChainSectorInfo, error)
|
StateMinerProvingSet(context.Context, address.Address, types.TipSetKey) ([]*ChainSectorInfo, error)
|
||||||
StateMinerProvingDeadline(context.Context, address.Address, types.TipSetKey) (*miner.DeadlineInfo, error)
|
StateMinerProvingDeadline(context.Context, address.Address, types.TipSetKey) (*miner.DeadlineInfo, error)
|
||||||
StateMinerPower(context.Context, address.Address, types.TipSetKey) (*MinerPower, error)
|
StateMinerPower(context.Context, address.Address, types.TipSetKey) (*MinerPower, error)
|
||||||
StateMinerInfo(context.Context, address.Address, types.TipSetKey) (miner.MinerInfo, error)
|
StateMinerInfo(context.Context, address.Address, types.TipSetKey) (MinerInfo, error)
|
||||||
StateMinerDeadlines(context.Context, address.Address, types.TipSetKey) (*miner.Deadlines, error)
|
StateMinerDeadlines(context.Context, address.Address, types.TipSetKey) (*miner.Deadlines, error)
|
||||||
StateMinerFaults(context.Context, address.Address, types.TipSetKey) (*abi.BitField, error)
|
StateMinerFaults(context.Context, address.Address, types.TipSetKey) (*abi.BitField, error)
|
||||||
// Returns all non-expired Faults that occur within lookback epochs of the given tipset
|
// Returns all non-expired Faults that occur within lookback epochs of the given tipset
|
||||||
@@ -156,7 +225,7 @@ type FullNode interface {
|
|||||||
StateSectorPreCommitInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error)
|
StateSectorPreCommitInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error)
|
||||||
StateSectorGetInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorOnChainInfo, error)
|
StateSectorGetInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorOnChainInfo, error)
|
||||||
StatePledgeCollateral(context.Context, types.TipSetKey) (types.BigInt, error)
|
StatePledgeCollateral(context.Context, types.TipSetKey) (types.BigInt, error)
|
||||||
StateWaitMsg(context.Context, cid.Cid) (*MsgLookup, error)
|
StateWaitMsg(ctx context.Context, cid cid.Cid, confidence uint64) (*MsgLookup, error)
|
||||||
StateSearchMsg(context.Context, cid.Cid) (*MsgLookup, error)
|
StateSearchMsg(context.Context, cid.Cid) (*MsgLookup, error)
|
||||||
StateListMiners(context.Context, types.TipSetKey) ([]address.Address, error)
|
StateListMiners(context.Context, types.TipSetKey) ([]address.Address, error)
|
||||||
StateListActors(context.Context, types.TipSetKey) ([]address.Address, error)
|
StateListActors(context.Context, types.TipSetKey) ([]address.Address, error)
|
||||||
@@ -349,11 +418,11 @@ type RetrievalOrder struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type InvocResult struct {
|
type InvocResult struct {
|
||||||
Msg *types.Message
|
Msg *types.Message
|
||||||
MsgRct *types.MessageReceipt
|
MsgRct *types.MessageReceipt
|
||||||
InternalExecutions []*types.ExecutionResult
|
ExecutionTrace types.ExecutionTrace
|
||||||
Error string
|
Error string
|
||||||
Duration time.Duration
|
Duration time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
type MethodCall struct {
|
type MethodCall struct {
|
||||||
|
|||||||
+13
-1
@@ -36,6 +36,7 @@ type StorageMiner interface {
|
|||||||
SectorsRefs(context.Context) (map[string][]SealedRef, error)
|
SectorsRefs(context.Context) (map[string][]SealedRef, error)
|
||||||
|
|
||||||
SectorsUpdate(context.Context, abi.SectorNumber, SectorState) error
|
SectorsUpdate(context.Context, abi.SectorNumber, SectorState) error
|
||||||
|
SectorRemove(context.Context, abi.SectorNumber) error
|
||||||
|
|
||||||
StorageList(ctx context.Context) (map[stores.ID][]stores.Decl, error)
|
StorageList(ctx context.Context) (map[stores.ID][]stores.Decl, error)
|
||||||
StorageLocal(ctx context.Context) (map[stores.ID]string, error)
|
StorageLocal(ctx context.Context) (map[stores.ID]string, error)
|
||||||
@@ -50,10 +51,21 @@ type StorageMiner interface {
|
|||||||
MarketImportDealData(ctx context.Context, propcid cid.Cid, path string) error
|
MarketImportDealData(ctx context.Context, propcid cid.Cid, path string) error
|
||||||
MarketListDeals(ctx context.Context) ([]storagemarket.StorageDeal, error)
|
MarketListDeals(ctx context.Context) ([]storagemarket.StorageDeal, error)
|
||||||
MarketListIncompleteDeals(ctx context.Context) ([]storagemarket.MinerDeal, error)
|
MarketListIncompleteDeals(ctx context.Context) ([]storagemarket.MinerDeal, error)
|
||||||
MarketSetPrice(context.Context, types.BigInt) error
|
MarketSetAsk(ctx context.Context, price types.BigInt, duration abi.ChainEpoch, minPieceSize abi.PaddedPieceSize, maxPieceSize abi.PaddedPieceSize) error
|
||||||
|
MarketGetAsk(ctx context.Context) (*storagemarket.SignedStorageAsk, error)
|
||||||
|
|
||||||
DealsImportData(ctx context.Context, dealPropCid cid.Cid, file string) error
|
DealsImportData(ctx context.Context, dealPropCid cid.Cid, file string) error
|
||||||
DealsList(ctx context.Context) ([]storagemarket.StorageDeal, error)
|
DealsList(ctx context.Context) ([]storagemarket.StorageDeal, error)
|
||||||
|
DealsConsiderOnlineStorageDeals(context.Context) (bool, error)
|
||||||
|
DealsSetConsiderOnlineStorageDeals(context.Context, bool) error
|
||||||
|
DealsConsiderOnlineRetrievalDeals(context.Context) (bool, error)
|
||||||
|
DealsSetConsiderOnlineRetrievalDeals(context.Context, bool) error
|
||||||
|
DealsPieceCidBlocklist(context.Context) ([]cid.Cid, error)
|
||||||
|
DealsSetPieceCidBlocklist(context.Context, []cid.Cid) error
|
||||||
|
DealsConsiderOfflineStorageDeals(context.Context) (bool, error)
|
||||||
|
DealsSetConsiderOfflineStorageDeals(context.Context, bool) error
|
||||||
|
DealsConsiderOfflineRetrievalDeals(context.Context) (bool, error)
|
||||||
|
DealsSetConsiderOfflineRetrievalDeals(context.Context, bool) error
|
||||||
|
|
||||||
StorageAddLocal(ctx context.Context, path string) error
|
StorageAddLocal(ctx context.Context, path string) error
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -25,10 +25,12 @@ type WorkerAPI interface {
|
|||||||
|
|
||||||
storage.Sealer
|
storage.Sealer
|
||||||
|
|
||||||
|
MoveStorage(ctx context.Context, sector abi.SectorID) error
|
||||||
|
|
||||||
UnsealPiece(context.Context, abi.SectorID, storiface.UnpaddedByteIndex, abi.UnpaddedPieceSize, abi.SealRandomness, cid.Cid) error
|
UnsealPiece(context.Context, abi.SectorID, storiface.UnpaddedByteIndex, abi.UnpaddedPieceSize, abi.SealRandomness, cid.Cid) error
|
||||||
ReadPiece(context.Context, io.Writer, abi.SectorID, storiface.UnpaddedByteIndex, abi.UnpaddedPieceSize) error
|
ReadPiece(context.Context, io.Writer, abi.SectorID, storiface.UnpaddedByteIndex, abi.UnpaddedPieceSize) error
|
||||||
|
|
||||||
Fetch(context.Context, abi.SectorID, stores.SectorFileType, bool, stores.AcquireMode) error
|
Fetch(context.Context, abi.SectorID, stores.SectorFileType, stores.PathType, stores.AcquireMode) error
|
||||||
|
|
||||||
Closing(context.Context) (<-chan struct{}, error)
|
Closing(context.Context) (<-chan struct{}, error)
|
||||||
}
|
}
|
||||||
|
|||||||
+158
-48
@@ -42,12 +42,16 @@ type CommonStruct struct {
|
|||||||
NetAddrsListen func(context.Context) (peer.AddrInfo, error) `perm:"read"`
|
NetAddrsListen func(context.Context) (peer.AddrInfo, error) `perm:"read"`
|
||||||
NetDisconnect func(context.Context, peer.ID) error `perm:"write"`
|
NetDisconnect func(context.Context, peer.ID) error `perm:"write"`
|
||||||
NetFindPeer func(context.Context, peer.ID) (peer.AddrInfo, error) `perm:"read"`
|
NetFindPeer func(context.Context, peer.ID) (peer.AddrInfo, error) `perm:"read"`
|
||||||
|
NetPubsubScores func(context.Context) ([]api.PubsubScore, error) `perm:"read"`
|
||||||
|
|
||||||
ID func(context.Context) (peer.ID, error) `perm:"read"`
|
ID func(context.Context) (peer.ID, error) `perm:"read"`
|
||||||
Version func(context.Context) (api.Version, error) `perm:"read"`
|
Version func(context.Context) (api.Version, error) `perm:"read"`
|
||||||
|
|
||||||
LogList func(context.Context) ([]string, error) `perm:"write"`
|
LogList func(context.Context) ([]string, error) `perm:"write"`
|
||||||
LogSetLevel func(context.Context, string, string) error `perm:"write"`
|
LogSetLevel func(context.Context, string, string) error `perm:"write"`
|
||||||
|
|
||||||
|
Shutdown func(context.Context) error `perm:"admin"`
|
||||||
|
Closing func(context.Context) (<-chan struct{}, error) `perm:"read"`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,25 +107,27 @@ type FullNodeStruct struct {
|
|||||||
WalletSetDefault func(context.Context, address.Address) error `perm:"admin"`
|
WalletSetDefault func(context.Context, address.Address) error `perm:"admin"`
|
||||||
WalletExport func(context.Context, address.Address) (*types.KeyInfo, error) `perm:"admin"`
|
WalletExport func(context.Context, address.Address) (*types.KeyInfo, error) `perm:"admin"`
|
||||||
WalletImport func(context.Context, *types.KeyInfo) (address.Address, error) `perm:"admin"`
|
WalletImport func(context.Context, *types.KeyInfo) (address.Address, error) `perm:"admin"`
|
||||||
|
WalletDelete func(context.Context, address.Address) error `perm:"write"`
|
||||||
|
|
||||||
ClientImport func(ctx context.Context, ref api.FileRef) (cid.Cid, error) `perm:"admin"`
|
ClientImport func(ctx context.Context, ref api.FileRef) (cid.Cid, error) `perm:"admin"`
|
||||||
ClientListImports func(ctx context.Context) ([]api.Import, error) `perm:"write"`
|
ClientListImports func(ctx context.Context) ([]api.Import, error) `perm:"write"`
|
||||||
ClientHasLocal func(ctx context.Context, root cid.Cid) (bool, error) `perm:"write"`
|
ClientHasLocal func(ctx context.Context, root cid.Cid) (bool, error) `perm:"write"`
|
||||||
ClientFindData func(ctx context.Context, root cid.Cid) ([]api.QueryOffer, error) `perm:"read"`
|
ClientFindData func(ctx context.Context, root cid.Cid) ([]api.QueryOffer, error) `perm:"read"`
|
||||||
ClientStartDeal func(ctx context.Context, params *api.StartDealParams) (*cid.Cid, error) `perm:"admin"`
|
ClientMinerQueryOffer func(ctx context.Context, root cid.Cid, miner address.Address) (api.QueryOffer, error) `perm:"read"`
|
||||||
ClientGetDealInfo func(context.Context, cid.Cid) (*api.DealInfo, error) `perm:"read"`
|
ClientStartDeal func(ctx context.Context, params *api.StartDealParams) (*cid.Cid, error) `perm:"admin"`
|
||||||
ClientListDeals func(ctx context.Context) ([]api.DealInfo, error) `perm:"write"`
|
ClientGetDealInfo func(context.Context, cid.Cid) (*api.DealInfo, error) `perm:"read"`
|
||||||
ClientRetrieve func(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) error `perm:"admin"`
|
ClientListDeals func(ctx context.Context) ([]api.DealInfo, error) `perm:"write"`
|
||||||
ClientQueryAsk func(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.SignedStorageAsk, error) `perm:"read"`
|
ClientRetrieve func(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) error `perm:"admin"`
|
||||||
ClientCalcCommP func(ctx context.Context, inpath string, miner address.Address) (*api.CommPRet, error) `perm:"read"`
|
ClientQueryAsk func(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.SignedStorageAsk, error) `perm:"read"`
|
||||||
ClientGenCar func(ctx context.Context, ref api.FileRef, outpath string) error `perm:"write"`
|
ClientCalcCommP func(ctx context.Context, inpath string, miner address.Address) (*api.CommPRet, error) `perm:"read"`
|
||||||
|
ClientGenCar func(ctx context.Context, ref api.FileRef, outpath string) error `perm:"write"`
|
||||||
|
|
||||||
StateNetworkName func(context.Context) (dtypes.NetworkName, error) `perm:"read"`
|
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, *abi.BitField, bool, types.TipSetKey) ([]*api.ChainSectorInfo, error) `perm:"read"`
|
||||||
StateMinerProvingSet func(context.Context, address.Address, types.TipSetKey) ([]*api.ChainSectorInfo, error) `perm:"read"`
|
StateMinerProvingSet func(context.Context, address.Address, types.TipSetKey) ([]*api.ChainSectorInfo, error) `perm:"read"`
|
||||||
StateMinerProvingDeadline func(context.Context, address.Address, types.TipSetKey) (*miner.DeadlineInfo, error) `perm:"read"`
|
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"`
|
StateMinerPower func(context.Context, address.Address, types.TipSetKey) (*api.MinerPower, error) `perm:"read"`
|
||||||
StateMinerInfo func(context.Context, address.Address, types.TipSetKey) (miner.MinerInfo, error) `perm:"read"`
|
StateMinerInfo func(context.Context, address.Address, types.TipSetKey) (api.MinerInfo, error) `perm:"read"`
|
||||||
StateMinerDeadlines func(context.Context, address.Address, types.TipSetKey) (*miner.Deadlines, error) `perm:"read"`
|
StateMinerDeadlines func(context.Context, address.Address, types.TipSetKey) (*miner.Deadlines, error) `perm:"read"`
|
||||||
StateMinerFaults func(context.Context, address.Address, types.TipSetKey) (*abi.BitField, error) `perm:"read"`
|
StateMinerFaults func(context.Context, address.Address, types.TipSetKey) (*abi.BitField, error) `perm:"read"`
|
||||||
StateAllMinerFaults func(context.Context, abi.ChainEpoch, types.TipSetKey) ([]*api.Fault, error) `perm:"read"`
|
StateAllMinerFaults func(context.Context, abi.ChainEpoch, types.TipSetKey) ([]*api.Fault, error) `perm:"read"`
|
||||||
@@ -133,9 +139,9 @@ type FullNodeStruct struct {
|
|||||||
StateCall func(context.Context, *types.Message, types.TipSetKey) (*api.InvocResult, error) `perm:"read"`
|
StateCall func(context.Context, *types.Message, types.TipSetKey) (*api.InvocResult, error) `perm:"read"`
|
||||||
StateReplay func(context.Context, types.TipSetKey, cid.Cid) (*api.InvocResult, error) `perm:"read"`
|
StateReplay func(context.Context, types.TipSetKey, cid.Cid) (*api.InvocResult, error) `perm:"read"`
|
||||||
StateGetActor func(context.Context, address.Address, types.TipSetKey) (*types.Actor, error) `perm:"read"`
|
StateGetActor func(context.Context, address.Address, types.TipSetKey) (*types.Actor, error) `perm:"read"`
|
||||||
StateReadState func(context.Context, *types.Actor, types.TipSetKey) (*api.ActorState, error) `perm:"read"`
|
StateReadState func(context.Context, address.Address, types.TipSetKey) (*api.ActorState, error) `perm:"read"`
|
||||||
StatePledgeCollateral func(context.Context, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
StatePledgeCollateral func(context.Context, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||||
StateWaitMsg func(context.Context, cid.Cid) (*api.MsgLookup, error) `perm:"read"`
|
StateWaitMsg func(ctx context.Context, cid cid.Cid, confidence uint64) (*api.MsgLookup, error) `perm:"read"`
|
||||||
StateSearchMsg func(context.Context, cid.Cid) (*api.MsgLookup, error) `perm:"read"`
|
StateSearchMsg func(context.Context, cid.Cid) (*api.MsgLookup, error) `perm:"read"`
|
||||||
StateListMiners func(context.Context, types.TipSetKey) ([]address.Address, error) `perm:"read"`
|
StateListMiners func(context.Context, types.TipSetKey) ([]address.Address, error) `perm:"read"`
|
||||||
StateListActors func(context.Context, types.TipSetKey) ([]address.Address, error) `perm:"read"`
|
StateListActors func(context.Context, types.TipSetKey) ([]address.Address, error) `perm:"read"`
|
||||||
@@ -188,10 +194,11 @@ type StorageMinerStruct struct {
|
|||||||
|
|
||||||
MiningBase func(context.Context) (*types.TipSet, error) `perm:"read"`
|
MiningBase func(context.Context) (*types.TipSet, error) `perm:"read"`
|
||||||
|
|
||||||
MarketImportDealData func(context.Context, cid.Cid, string) error `perm:"write"`
|
MarketImportDealData func(context.Context, cid.Cid, string) error `perm:"write"`
|
||||||
MarketListDeals func(ctx context.Context) ([]storagemarket.StorageDeal, error) `perm:"read"`
|
MarketListDeals func(ctx context.Context) ([]storagemarket.StorageDeal, error) `perm:"read"`
|
||||||
MarketListIncompleteDeals func(ctx context.Context) ([]storagemarket.MinerDeal, error) `perm:"read"`
|
MarketListIncompleteDeals func(ctx context.Context) ([]storagemarket.MinerDeal, error) `perm:"read"`
|
||||||
MarketSetPrice func(context.Context, types.BigInt) error `perm:"admin"`
|
MarketSetAsk func(ctx context.Context, price types.BigInt, duration abi.ChainEpoch, minPieceSize abi.PaddedPieceSize, maxPieceSize abi.PaddedPieceSize) error `perm:"admin"`
|
||||||
|
MarketGetAsk func(ctx context.Context) (*storagemarket.SignedStorageAsk, error) `perm:"read"`
|
||||||
|
|
||||||
PledgeSector func(context.Context) error `perm:"write"`
|
PledgeSector func(context.Context) error `perm:"write"`
|
||||||
|
|
||||||
@@ -199,23 +206,36 @@ type StorageMinerStruct struct {
|
|||||||
SectorsList func(context.Context) ([]abi.SectorNumber, error) `perm:"read"`
|
SectorsList func(context.Context) ([]abi.SectorNumber, error) `perm:"read"`
|
||||||
SectorsRefs func(context.Context) (map[string][]api.SealedRef, error) `perm:"read"`
|
SectorsRefs func(context.Context) (map[string][]api.SealedRef, error) `perm:"read"`
|
||||||
SectorsUpdate func(context.Context, abi.SectorNumber, api.SectorState) error `perm:"write"`
|
SectorsUpdate func(context.Context, abi.SectorNumber, api.SectorState) error `perm:"write"`
|
||||||
|
SectorRemove func(context.Context, abi.SectorNumber) error `perm:"admin"`
|
||||||
|
|
||||||
WorkerConnect func(context.Context, string) error `perm:"admin"` // TODO: worker perm
|
WorkerConnect func(context.Context, string) error `perm:"admin"` // TODO: worker perm
|
||||||
WorkerStats func(context.Context) (map[uint64]storiface.WorkerStats, error) `perm:"admin"`
|
WorkerStats func(context.Context) (map[uint64]storiface.WorkerStats, error) `perm:"admin"`
|
||||||
|
|
||||||
StorageList func(context.Context) (map[stores.ID][]stores.Decl, error) `perm:"admin"`
|
StorageList func(context.Context) (map[stores.ID][]stores.Decl, error) `perm:"admin"`
|
||||||
StorageLocal func(context.Context) (map[stores.ID]string, error) `perm:"admin"`
|
StorageLocal func(context.Context) (map[stores.ID]string, error) `perm:"admin"`
|
||||||
StorageStat func(context.Context, stores.ID) (stores.FsStat, error) `perm:"admin"`
|
StorageStat func(context.Context, stores.ID) (stores.FsStat, error) `perm:"admin"`
|
||||||
StorageAttach func(context.Context, stores.StorageInfo, stores.FsStat) error `perm:"admin"`
|
StorageAttach func(context.Context, stores.StorageInfo, stores.FsStat) error `perm:"admin"`
|
||||||
StorageDeclareSector func(context.Context, stores.ID, abi.SectorID, stores.SectorFileType, bool) error `perm:"admin"`
|
StorageDeclareSector func(context.Context, stores.ID, abi.SectorID, stores.SectorFileType, bool) error `perm:"admin"`
|
||||||
StorageDropSector func(context.Context, stores.ID, abi.SectorID, stores.SectorFileType) error `perm:"admin"`
|
StorageDropSector func(context.Context, stores.ID, abi.SectorID, stores.SectorFileType) error `perm:"admin"`
|
||||||
StorageFindSector func(context.Context, abi.SectorID, stores.SectorFileType, bool) ([]stores.SectorStorageInfo, error) `perm:"admin"`
|
StorageFindSector func(context.Context, abi.SectorID, stores.SectorFileType, bool) ([]stores.SectorStorageInfo, error) `perm:"admin"`
|
||||||
StorageInfo func(context.Context, stores.ID) (stores.StorageInfo, error) `perm:"admin"`
|
StorageInfo func(context.Context, stores.ID) (stores.StorageInfo, error) `perm:"admin"`
|
||||||
StorageBestAlloc func(ctx context.Context, allocate stores.SectorFileType, spt abi.RegisteredProof, sealing stores.PathType) ([]stores.StorageInfo, error) `perm:"admin"`
|
StorageBestAlloc func(ctx context.Context, allocate stores.SectorFileType, spt abi.RegisteredSealProof, sealing stores.PathType) ([]stores.StorageInfo, error) `perm:"admin"`
|
||||||
StorageReportHealth func(ctx context.Context, id stores.ID, report stores.HealthReport) error `perm:"admin"`
|
StorageReportHealth func(ctx context.Context, id stores.ID, report stores.HealthReport) error `perm:"admin"`
|
||||||
|
StorageLock func(ctx context.Context, sector abi.SectorID, read stores.SectorFileType, write stores.SectorFileType) error `perm:"admin"`
|
||||||
|
StorageTryLock func(ctx context.Context, sector abi.SectorID, read stores.SectorFileType, write stores.SectorFileType) (bool, error) `perm:"admin"`
|
||||||
|
|
||||||
DealsImportData func(ctx context.Context, dealPropCid cid.Cid, file string) error `perm:"write"`
|
DealsImportData func(ctx context.Context, dealPropCid cid.Cid, file string) error `perm:"write"`
|
||||||
DealsList func(ctx context.Context) ([]storagemarket.StorageDeal, error) `perm:"read"`
|
DealsList func(ctx context.Context) ([]storagemarket.StorageDeal, error) `perm:"read"`
|
||||||
|
DealsConsiderOnlineStorageDeals func(context.Context) (bool, error) `perm:"read"`
|
||||||
|
DealsSetConsiderOnlineStorageDeals func(context.Context, bool) error `perm:"admin"`
|
||||||
|
DealsConsiderOnlineRetrievalDeals func(context.Context) (bool, error) `perm:"read"`
|
||||||
|
DealsSetConsiderOnlineRetrievalDeals func(context.Context, bool) error `perm:"admin"`
|
||||||
|
DealsConsiderOfflineStorageDeals func(context.Context) (bool, error) `perm:"read"`
|
||||||
|
DealsSetConsiderOfflineStorageDeals func(context.Context, bool) error `perm:"admin"`
|
||||||
|
DealsConsiderOfflineRetrievalDeals func(context.Context) (bool, error) `perm:"read"`
|
||||||
|
DealsSetConsiderOfflineRetrievalDeals func(context.Context, bool) error `perm:"admin"`
|
||||||
|
DealsPieceCidBlocklist func(context.Context) ([]cid.Cid, error) `perm:"read"`
|
||||||
|
DealsSetPieceCidBlocklist func(context.Context, []cid.Cid) error `perm:"admin"`
|
||||||
|
|
||||||
StorageAddLocal func(ctx context.Context, path string) error `perm:"admin"`
|
StorageAddLocal func(ctx context.Context, path string) error `perm:"admin"`
|
||||||
}
|
}
|
||||||
@@ -231,16 +251,19 @@ type WorkerStruct struct {
|
|||||||
Paths func(context.Context) ([]stores.StoragePath, error) `perm:"admin"`
|
Paths func(context.Context) ([]stores.StoragePath, error) `perm:"admin"`
|
||||||
Info func(context.Context) (storiface.WorkerInfo, error) `perm:"admin"`
|
Info func(context.Context) (storiface.WorkerInfo, error) `perm:"admin"`
|
||||||
|
|
||||||
SealPreCommit1 func(ctx context.Context, sector abi.SectorID, ticket abi.SealRandomness, pieces []abi.PieceInfo) (storage.PreCommit1Out, 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"`
|
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"`
|
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"`
|
||||||
SealCommit2 func(context.Context, abi.SectorID, storage.Commit1Out) (storage.Proof, error) `perm:"admin"`
|
SealCommit2 func(context.Context, abi.SectorID, storage.Commit1Out) (storage.Proof, error) `perm:"admin"`
|
||||||
FinalizeSector func(context.Context, abi.SectorID) error `perm:"admin"`
|
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"`
|
||||||
|
|
||||||
UnsealPiece func(context.Context, abi.SectorID, storiface.UnpaddedByteIndex, abi.UnpaddedPieceSize, abi.SealRandomness, cid.Cid) error `perm:"admin"`
|
UnsealPiece func(context.Context, abi.SectorID, storiface.UnpaddedByteIndex, abi.UnpaddedPieceSize, abi.SealRandomness, cid.Cid) error `perm:"admin"`
|
||||||
ReadPiece func(context.Context, io.Writer, abi.SectorID, storiface.UnpaddedByteIndex, abi.UnpaddedPieceSize) error `perm:"admin"`
|
ReadPiece func(context.Context, io.Writer, abi.SectorID, storiface.UnpaddedByteIndex, abi.UnpaddedPieceSize) error `perm:"admin"`
|
||||||
|
|
||||||
Fetch func(context.Context, abi.SectorID, stores.SectorFileType, bool, stores.AcquireMode) error `perm:"admin"`
|
Fetch func(context.Context, abi.SectorID, stores.SectorFileType, stores.PathType, stores.AcquireMode) error `perm:"admin"`
|
||||||
|
|
||||||
Closing func(context.Context) (<-chan struct{}, error) `perm:"admin"`
|
Closing func(context.Context) (<-chan struct{}, error) `perm:"admin"`
|
||||||
}
|
}
|
||||||
@@ -256,6 +279,9 @@ func (c *CommonStruct) AuthNew(ctx context.Context, perms []auth.Permission) ([]
|
|||||||
return c.Internal.AuthNew(ctx, perms)
|
return c.Internal.AuthNew(ctx, perms)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *CommonStruct) NetPubsubScores(ctx context.Context) ([]api.PubsubScore, error) {
|
||||||
|
return c.Internal.NetPubsubScores(ctx)
|
||||||
|
}
|
||||||
func (c *CommonStruct) NetConnectedness(ctx context.Context, pid peer.ID) (network.Connectedness, error) {
|
func (c *CommonStruct) NetConnectedness(ctx context.Context, pid peer.ID) (network.Connectedness, error) {
|
||||||
return c.Internal.NetConnectedness(ctx, pid)
|
return c.Internal.NetConnectedness(ctx, pid)
|
||||||
}
|
}
|
||||||
@@ -298,6 +324,14 @@ func (c *CommonStruct) LogSetLevel(ctx context.Context, group, level string) err
|
|||||||
return c.Internal.LogSetLevel(ctx, group, level)
|
return c.Internal.LogSetLevel(ctx, group, level)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *CommonStruct) Shutdown(ctx context.Context) error {
|
||||||
|
return c.Internal.Shutdown(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CommonStruct) Closing(ctx context.Context) (<-chan struct{}, error) {
|
||||||
|
return c.Internal.Closing(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
// FullNodeStruct
|
// FullNodeStruct
|
||||||
|
|
||||||
func (c *FullNodeStruct) ClientListImports(ctx context.Context) ([]api.Import, error) {
|
func (c *FullNodeStruct) ClientListImports(ctx context.Context) ([]api.Import, error) {
|
||||||
@@ -316,6 +350,10 @@ func (c *FullNodeStruct) ClientFindData(ctx context.Context, root cid.Cid) ([]ap
|
|||||||
return c.Internal.ClientFindData(ctx, root)
|
return c.Internal.ClientFindData(ctx, root)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *FullNodeStruct) ClientMinerQueryOffer(ctx context.Context, root cid.Cid, miner address.Address) (api.QueryOffer, error) {
|
||||||
|
return c.Internal.ClientMinerQueryOffer(ctx, root, miner)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *FullNodeStruct) ClientStartDeal(ctx context.Context, params *api.StartDealParams) (*cid.Cid, error) {
|
func (c *FullNodeStruct) ClientStartDeal(ctx context.Context, params *api.StartDealParams) (*cid.Cid, error) {
|
||||||
return c.Internal.ClientStartDeal(ctx, params)
|
return c.Internal.ClientStartDeal(ctx, params)
|
||||||
}
|
}
|
||||||
@@ -426,6 +464,10 @@ func (c *FullNodeStruct) WalletImport(ctx context.Context, ki *types.KeyInfo) (a
|
|||||||
return c.Internal.WalletImport(ctx, ki)
|
return c.Internal.WalletImport(ctx, ki)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *FullNodeStruct) WalletDelete(ctx context.Context, addr address.Address) error {
|
||||||
|
return c.Internal.WalletDelete(ctx, addr)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *FullNodeStruct) MpoolGetNonce(ctx context.Context, addr address.Address) (uint64, error) {
|
func (c *FullNodeStruct) MpoolGetNonce(ctx context.Context, addr address.Address) (uint64, error) {
|
||||||
return c.Internal.MpoolGetNonce(ctx, addr)
|
return c.Internal.MpoolGetNonce(ctx, addr)
|
||||||
}
|
}
|
||||||
@@ -534,7 +576,7 @@ func (c *FullNodeStruct) StateMinerPower(ctx context.Context, a address.Address,
|
|||||||
return c.Internal.StateMinerPower(ctx, a, tsk)
|
return c.Internal.StateMinerPower(ctx, a, tsk)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *FullNodeStruct) StateMinerInfo(ctx context.Context, actor address.Address, tsk types.TipSetKey) (miner.MinerInfo, error) {
|
func (c *FullNodeStruct) StateMinerInfo(ctx context.Context, actor address.Address, tsk types.TipSetKey) (api.MinerInfo, error) {
|
||||||
return c.Internal.StateMinerInfo(ctx, actor, tsk)
|
return c.Internal.StateMinerInfo(ctx, actor, tsk)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -582,16 +624,16 @@ func (c *FullNodeStruct) StateGetActor(ctx context.Context, actor address.Addres
|
|||||||
return c.Internal.StateGetActor(ctx, actor, tsk)
|
return c.Internal.StateGetActor(ctx, actor, tsk)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *FullNodeStruct) StateReadState(ctx context.Context, act *types.Actor, tsk types.TipSetKey) (*api.ActorState, error) {
|
func (c *FullNodeStruct) StateReadState(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*api.ActorState, error) {
|
||||||
return c.Internal.StateReadState(ctx, act, tsk)
|
return c.Internal.StateReadState(ctx, addr, tsk)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *FullNodeStruct) StatePledgeCollateral(ctx context.Context, tsk types.TipSetKey) (types.BigInt, error) {
|
func (c *FullNodeStruct) StatePledgeCollateral(ctx context.Context, tsk types.TipSetKey) (types.BigInt, error) {
|
||||||
return c.Internal.StatePledgeCollateral(ctx, tsk)
|
return c.Internal.StatePledgeCollateral(ctx, tsk)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *FullNodeStruct) StateWaitMsg(ctx context.Context, msgc cid.Cid) (*api.MsgLookup, error) {
|
func (c *FullNodeStruct) StateWaitMsg(ctx context.Context, msgc cid.Cid, confidence uint64) (*api.MsgLookup, error) {
|
||||||
return c.Internal.StateWaitMsg(ctx, msgc)
|
return c.Internal.StateWaitMsg(ctx, msgc, confidence)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *FullNodeStruct) StateSearchMsg(ctx context.Context, msgc cid.Cid) (*api.MsgLookup, error) {
|
func (c *FullNodeStruct) StateSearchMsg(ctx context.Context, msgc cid.Cid) (*api.MsgLookup, error) {
|
||||||
@@ -754,6 +796,10 @@ func (c *StorageMinerStruct) SectorsUpdate(ctx context.Context, id abi.SectorNum
|
|||||||
return c.Internal.SectorsUpdate(ctx, id, state)
|
return c.Internal.SectorsUpdate(ctx, id, state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *StorageMinerStruct) SectorRemove(ctx context.Context, number abi.SectorNumber) error {
|
||||||
|
return c.Internal.SectorRemove(ctx, number)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *StorageMinerStruct) WorkerConnect(ctx context.Context, url string) error {
|
func (c *StorageMinerStruct) WorkerConnect(ctx context.Context, url string) error {
|
||||||
return c.Internal.WorkerConnect(ctx, url)
|
return c.Internal.WorkerConnect(ctx, url)
|
||||||
}
|
}
|
||||||
@@ -794,7 +840,7 @@ func (c *StorageMinerStruct) StorageInfo(ctx context.Context, id stores.ID) (sto
|
|||||||
return c.Internal.StorageInfo(ctx, id)
|
return c.Internal.StorageInfo(ctx, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StorageMinerStruct) StorageBestAlloc(ctx context.Context, allocate stores.SectorFileType, spt abi.RegisteredProof, pt stores.PathType) ([]stores.StorageInfo, error) {
|
func (c *StorageMinerStruct) StorageBestAlloc(ctx context.Context, allocate stores.SectorFileType, spt abi.RegisteredSealProof, pt stores.PathType) ([]stores.StorageInfo, error) {
|
||||||
return c.Internal.StorageBestAlloc(ctx, allocate, spt, pt)
|
return c.Internal.StorageBestAlloc(ctx, allocate, spt, pt)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -802,6 +848,14 @@ func (c *StorageMinerStruct) StorageReportHealth(ctx context.Context, id stores.
|
|||||||
return c.Internal.StorageReportHealth(ctx, id, report)
|
return c.Internal.StorageReportHealth(ctx, id, report)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *StorageMinerStruct) StorageLock(ctx context.Context, sector abi.SectorID, read stores.SectorFileType, write stores.SectorFileType) error {
|
||||||
|
return c.Internal.StorageLock(ctx, sector, read, write)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *StorageMinerStruct) StorageTryLock(ctx context.Context, sector abi.SectorID, read stores.SectorFileType, write stores.SectorFileType) (bool, error) {
|
||||||
|
return c.Internal.StorageTryLock(ctx, sector, read, write)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *StorageMinerStruct) MarketImportDealData(ctx context.Context, propcid cid.Cid, path string) error {
|
func (c *StorageMinerStruct) MarketImportDealData(ctx context.Context, propcid cid.Cid, path string) error {
|
||||||
return c.Internal.MarketImportDealData(ctx, propcid, path)
|
return c.Internal.MarketImportDealData(ctx, propcid, path)
|
||||||
}
|
}
|
||||||
@@ -814,8 +868,12 @@ func (c *StorageMinerStruct) MarketListIncompleteDeals(ctx context.Context) ([]s
|
|||||||
return c.Internal.MarketListIncompleteDeals(ctx)
|
return c.Internal.MarketListIncompleteDeals(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StorageMinerStruct) MarketSetPrice(ctx context.Context, p types.BigInt) error {
|
func (c *StorageMinerStruct) MarketSetAsk(ctx context.Context, price types.BigInt, duration abi.ChainEpoch, minPieceSize abi.PaddedPieceSize, maxPieceSize abi.PaddedPieceSize) error {
|
||||||
return c.Internal.MarketSetPrice(ctx, p)
|
return c.Internal.MarketSetAsk(ctx, price, duration, minPieceSize, maxPieceSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *StorageMinerStruct) MarketGetAsk(ctx context.Context) (*storagemarket.SignedStorageAsk, error) {
|
||||||
|
return c.Internal.MarketGetAsk(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StorageMinerStruct) DealsImportData(ctx context.Context, dealPropCid cid.Cid, file string) error {
|
func (c *StorageMinerStruct) DealsImportData(ctx context.Context, dealPropCid cid.Cid, file string) error {
|
||||||
@@ -826,6 +884,46 @@ func (c *StorageMinerStruct) DealsList(ctx context.Context) ([]storagemarket.Sto
|
|||||||
return c.Internal.DealsList(ctx)
|
return c.Internal.DealsList(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *StorageMinerStruct) DealsConsiderOnlineStorageDeals(ctx context.Context) (bool, error) {
|
||||||
|
return c.Internal.DealsConsiderOnlineStorageDeals(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *StorageMinerStruct) DealsSetConsiderOnlineStorageDeals(ctx context.Context, b bool) error {
|
||||||
|
return c.Internal.DealsSetConsiderOnlineStorageDeals(ctx, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *StorageMinerStruct) DealsConsiderOnlineRetrievalDeals(ctx context.Context) (bool, error) {
|
||||||
|
return c.Internal.DealsConsiderOnlineRetrievalDeals(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *StorageMinerStruct) DealsSetConsiderOnlineRetrievalDeals(ctx context.Context, b bool) error {
|
||||||
|
return c.Internal.DealsSetConsiderOnlineRetrievalDeals(ctx, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *StorageMinerStruct) DealsPieceCidBlocklist(ctx context.Context) ([]cid.Cid, error) {
|
||||||
|
return c.Internal.DealsPieceCidBlocklist(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *StorageMinerStruct) DealsSetPieceCidBlocklist(ctx context.Context, cids []cid.Cid) error {
|
||||||
|
return c.Internal.DealsSetPieceCidBlocklist(ctx, cids)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *StorageMinerStruct) DealsConsiderOfflineStorageDeals(ctx context.Context) (bool, error) {
|
||||||
|
return c.Internal.DealsConsiderOfflineStorageDeals(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *StorageMinerStruct) DealsSetConsiderOfflineStorageDeals(ctx context.Context, b bool) error {
|
||||||
|
return c.Internal.DealsSetConsiderOfflineStorageDeals(ctx, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *StorageMinerStruct) DealsConsiderOfflineRetrievalDeals(ctx context.Context) (bool, error) {
|
||||||
|
return c.Internal.DealsConsiderOfflineRetrievalDeals(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *StorageMinerStruct) DealsSetConsiderOfflineRetrievalDeals(ctx context.Context, b bool) error {
|
||||||
|
return c.Internal.DealsSetConsiderOfflineRetrievalDeals(ctx, b)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *StorageMinerStruct) StorageAddLocal(ctx context.Context, path string) error {
|
func (c *StorageMinerStruct) StorageAddLocal(ctx context.Context, path string) error {
|
||||||
return c.Internal.StorageAddLocal(ctx, path)
|
return c.Internal.StorageAddLocal(ctx, path)
|
||||||
}
|
}
|
||||||
@@ -864,8 +962,20 @@ func (w *WorkerStruct) SealCommit2(ctx context.Context, sector abi.SectorID, c1o
|
|||||||
return w.Internal.SealCommit2(ctx, sector, c1o)
|
return w.Internal.SealCommit2(ctx, sector, c1o)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WorkerStruct) FinalizeSector(ctx context.Context, sector abi.SectorID) error {
|
func (w *WorkerStruct) FinalizeSector(ctx context.Context, sector abi.SectorID, keepUnsealed []storage.Range) error {
|
||||||
return w.Internal.FinalizeSector(ctx, sector)
|
return w.Internal.FinalizeSector(ctx, sector, keepUnsealed)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WorkerStruct) ReleaseUnsealed(ctx context.Context, sector abi.SectorID, safeToFree []storage.Range) error {
|
||||||
|
return w.Internal.ReleaseUnsealed(ctx, sector, safeToFree)
|
||||||
|
}
|
||||||
|
|
||||||
|
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) UnsealPiece(ctx context.Context, id abi.SectorID, index storiface.UnpaddedByteIndex, size abi.UnpaddedPieceSize, randomness abi.SealRandomness, c cid.Cid) error {
|
func (w *WorkerStruct) UnsealPiece(ctx context.Context, id abi.SectorID, index storiface.UnpaddedByteIndex, size abi.UnpaddedPieceSize, randomness abi.SealRandomness, c cid.Cid) error {
|
||||||
@@ -876,8 +986,8 @@ func (w *WorkerStruct) ReadPiece(ctx context.Context, writer io.Writer, id abi.S
|
|||||||
return w.Internal.ReadPiece(ctx, writer, id, index, size)
|
return w.Internal.ReadPiece(ctx, writer, id, index, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WorkerStruct) Fetch(ctx context.Context, id abi.SectorID, fileType stores.SectorFileType, b bool, am stores.AcquireMode) error {
|
func (w *WorkerStruct) Fetch(ctx context.Context, id abi.SectorID, fileType stores.SectorFileType, ptype stores.PathType, am stores.AcquireMode) error {
|
||||||
return w.Internal.Fetch(ctx, id, fileType, b, am)
|
return w.Internal.Fetch(ctx, id, fileType, ptype, am)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WorkerStruct) Closing(ctx context.Context) (<-chan struct{}, error) {
|
func (w *WorkerStruct) Closing(ctx context.Context) (<-chan struct{}, error) {
|
||||||
|
|||||||
+63
-23
@@ -16,6 +16,7 @@ import (
|
|||||||
"github.com/filecoin-project/go-bitfield"
|
"github.com/filecoin-project/go-bitfield"
|
||||||
"github.com/filecoin-project/go-jsonrpc/auth"
|
"github.com/filecoin-project/go-jsonrpc/auth"
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
|
"github.com/filecoin-project/lotus/api/apistruct"
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||||
@@ -72,10 +73,14 @@ func init() {
|
|||||||
addExample(pid)
|
addExample(pid)
|
||||||
|
|
||||||
addExample(bitfield.NewFromSet([]uint64{5}))
|
addExample(bitfield.NewFromSet([]uint64{5}))
|
||||||
addExample(abi.RegisteredProof_StackedDRG32GiBPoSt)
|
addExample(abi.RegisteredSealProof_StackedDrg32GiBV1)
|
||||||
|
addExample(abi.RegisteredPoStProof_StackedDrgWindow32GiBV1)
|
||||||
addExample(abi.ChainEpoch(10101))
|
addExample(abi.ChainEpoch(10101))
|
||||||
addExample(crypto.SigTypeBLS)
|
addExample(crypto.SigTypeBLS)
|
||||||
addExample(int64(9))
|
addExample(int64(9))
|
||||||
|
addExample(12.3)
|
||||||
|
addExample(123)
|
||||||
|
addExample(uintptr(0))
|
||||||
addExample(abi.MethodNum(1))
|
addExample(abi.MethodNum(1))
|
||||||
addExample(exitcode.ExitCode(0))
|
addExample(exitcode.ExitCode(0))
|
||||||
addExample(crypto.DomainSeparationTag_ElectionProofProduction)
|
addExample(crypto.DomainSeparationTag_ElectionProofProduction)
|
||||||
@@ -93,18 +98,18 @@ func init() {
|
|||||||
addExample(build.APIVersion)
|
addExample(build.APIVersion)
|
||||||
addExample(api.PCHInbound)
|
addExample(api.PCHInbound)
|
||||||
addExample(time.Minute)
|
addExample(time.Minute)
|
||||||
addExample(&types.ExecutionResult{
|
addExample(&types.ExecutionTrace{
|
||||||
Msg: exampleValue(reflect.TypeOf(&types.Message{})).(*types.Message),
|
Msg: exampleValue(reflect.TypeOf(&types.Message{}), nil).(*types.Message),
|
||||||
MsgRct: exampleValue(reflect.TypeOf(&types.MessageReceipt{})).(*types.MessageReceipt),
|
MsgRct: exampleValue(reflect.TypeOf(&types.MessageReceipt{}), nil).(*types.MessageReceipt),
|
||||||
})
|
})
|
||||||
addExample(map[string]types.Actor{
|
addExample(map[string]types.Actor{
|
||||||
"t01236": exampleValue(reflect.TypeOf(types.Actor{})).(types.Actor),
|
"t01236": exampleValue(reflect.TypeOf(types.Actor{}), nil).(types.Actor),
|
||||||
})
|
})
|
||||||
addExample(map[string]api.MarketDeal{
|
addExample(map[string]api.MarketDeal{
|
||||||
"t026363": exampleValue(reflect.TypeOf(api.MarketDeal{})).(api.MarketDeal),
|
"t026363": exampleValue(reflect.TypeOf(api.MarketDeal{}), nil).(api.MarketDeal),
|
||||||
})
|
})
|
||||||
addExample(map[string]api.MarketBalance{
|
addExample(map[string]api.MarketBalance{
|
||||||
"t026363": exampleValue(reflect.TypeOf(api.MarketBalance{})).(api.MarketBalance),
|
"t026363": exampleValue(reflect.TypeOf(api.MarketBalance{}), nil).(api.MarketBalance),
|
||||||
})
|
})
|
||||||
|
|
||||||
maddr, err := multiaddr.NewMultiaddr("/ip4/52.36.61.156/tcp/1347/p2p/12D3KooWFETiESTf1v4PGUvtnxMAcEFMzLZbJGg4tjWfGEimYior")
|
maddr, err := multiaddr.NewMultiaddr("/ip4/52.36.61.156/tcp/1347/p2p/12D3KooWFETiESTf1v4PGUvtnxMAcEFMzLZbJGg4tjWfGEimYior")
|
||||||
@@ -117,7 +122,7 @@ func init() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func exampleValue(t reflect.Type) interface{} {
|
func exampleValue(t, parent reflect.Type) interface{} {
|
||||||
v, ok := ExampleValues[t]
|
v, ok := ExampleValues[t]
|
||||||
if ok {
|
if ok {
|
||||||
return v
|
return v
|
||||||
@@ -126,25 +131,25 @@ func exampleValue(t reflect.Type) interface{} {
|
|||||||
switch t.Kind() {
|
switch t.Kind() {
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
out := reflect.New(t).Elem()
|
out := reflect.New(t).Elem()
|
||||||
reflect.Append(out, reflect.ValueOf(exampleValue(t.Elem())))
|
reflect.Append(out, reflect.ValueOf(exampleValue(t.Elem(), t)))
|
||||||
return out.Interface()
|
return out.Interface()
|
||||||
case reflect.Chan:
|
case reflect.Chan:
|
||||||
return exampleValue(t.Elem())
|
return exampleValue(t.Elem(), nil)
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
es := exampleStruct(t)
|
es := exampleStruct(t, parent)
|
||||||
v := reflect.ValueOf(es).Elem().Interface()
|
v := reflect.ValueOf(es).Elem().Interface()
|
||||||
ExampleValues[t] = v
|
ExampleValues[t] = v
|
||||||
return v
|
return v
|
||||||
case reflect.Array:
|
case reflect.Array:
|
||||||
out := reflect.New(t).Elem()
|
out := reflect.New(t).Elem()
|
||||||
for i := 0; i < t.Len(); i++ {
|
for i := 0; i < t.Len(); i++ {
|
||||||
out.Index(i).Set(reflect.ValueOf(exampleValue(t.Elem())))
|
out.Index(i).Set(reflect.ValueOf(exampleValue(t.Elem(), t)))
|
||||||
}
|
}
|
||||||
return out.Interface()
|
return out.Interface()
|
||||||
|
|
||||||
case reflect.Ptr:
|
case reflect.Ptr:
|
||||||
if t.Elem().Kind() == reflect.Struct {
|
if t.Elem().Kind() == reflect.Struct {
|
||||||
es := exampleStruct(t.Elem())
|
es := exampleStruct(t.Elem(), t)
|
||||||
//ExampleValues[t] = es
|
//ExampleValues[t] = es
|
||||||
return es
|
return es
|
||||||
}
|
}
|
||||||
@@ -155,12 +160,15 @@ func exampleValue(t reflect.Type) interface{} {
|
|||||||
panic(fmt.Sprintf("No example value for type: %s", t))
|
panic(fmt.Sprintf("No example value for type: %s", t))
|
||||||
}
|
}
|
||||||
|
|
||||||
func exampleStruct(t reflect.Type) interface{} {
|
func exampleStruct(t, parent reflect.Type) interface{} {
|
||||||
ns := reflect.New(t)
|
ns := reflect.New(t)
|
||||||
for i := 0; i < t.NumField(); i++ {
|
for i := 0; i < t.NumField(); i++ {
|
||||||
f := t.Field(i)
|
f := t.Field(i)
|
||||||
|
if f.Type == parent {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if strings.Title(f.Name) == f.Name {
|
if strings.Title(f.Name) == f.Name {
|
||||||
ns.Elem().Field(i).Set(reflect.ValueOf(exampleValue(f.Type)))
|
ns.Elem().Field(i).Set(reflect.ValueOf(exampleValue(f.Type, t)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,8 +201,7 @@ func (v *Visitor) Visit(node ast.Node) ast.Visitor {
|
|||||||
|
|
||||||
const noComment = "There are not yet any comments for this method."
|
const noComment = "There are not yet any comments for this method."
|
||||||
|
|
||||||
func parseApiASTInfo() (map[string]string, map[string]string) {
|
func parseApiASTInfo() (map[string]string, map[string]string) { //nolint:golint
|
||||||
|
|
||||||
fset := token.NewFileSet()
|
fset := token.NewFileSet()
|
||||||
pkgs, err := parser.ParseDir(fset, "./api", nil, parser.AllErrors|parser.ParseComments)
|
pkgs, err := parser.ParseDir(fset, "./api", nil, parser.AllErrors|parser.ParseComments)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -287,17 +294,17 @@ func main() {
|
|||||||
ft := m.Func.Type()
|
ft := m.Func.Type()
|
||||||
for j := 2; j < ft.NumIn(); j++ {
|
for j := 2; j < ft.NumIn(); j++ {
|
||||||
inp := ft.In(j)
|
inp := ft.In(j)
|
||||||
args = append(args, exampleValue(inp))
|
args = append(args, exampleValue(inp, nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
v, err := json.Marshal(args)
|
v, err := json.MarshalIndent(args, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
outv := exampleValue(ft.Out(0))
|
outv := exampleValue(ft.Out(0), nil)
|
||||||
|
|
||||||
ov, err := json.Marshal(outv)
|
ov, err := json.MarshalIndent(outv, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -319,6 +326,18 @@ func main() {
|
|||||||
return groupslice[i].GroupName < groupslice[j].GroupName
|
return groupslice[i].GroupName < groupslice[j].GroupName
|
||||||
})
|
})
|
||||||
|
|
||||||
|
fmt.Printf("# Groups\n")
|
||||||
|
|
||||||
|
for _, g := range groupslice {
|
||||||
|
fmt.Printf("* [%s](#%s)\n", g.GroupName, g.GroupName)
|
||||||
|
for _, method := range g.Methods {
|
||||||
|
fmt.Printf(" * [%s](#%s)\n", method.Name, method.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
permStruct := reflect.TypeOf(apistruct.FullNodeStruct{}.Internal)
|
||||||
|
commonPermStruct := reflect.TypeOf(apistruct.CommonStruct{}.Internal)
|
||||||
|
|
||||||
for _, g := range groupslice {
|
for _, g := range groupslice {
|
||||||
g := g
|
g := g
|
||||||
fmt.Printf("## %s\n", g.GroupName)
|
fmt.Printf("## %s\n", g.GroupName)
|
||||||
@@ -332,8 +351,29 @@ func main() {
|
|||||||
fmt.Printf("### %s\n", m.Name)
|
fmt.Printf("### %s\n", m.Name)
|
||||||
fmt.Printf("%s\n\n", m.Comment)
|
fmt.Printf("%s\n\n", m.Comment)
|
||||||
|
|
||||||
fmt.Printf("Inputs: `%s`\n\n", m.InputExample)
|
meth, ok := permStruct.FieldByName(m.Name)
|
||||||
fmt.Printf("Response: `%s`\n\n", m.ResponseExample)
|
if !ok {
|
||||||
|
meth, ok = commonPermStruct.FieldByName(m.Name)
|
||||||
|
if !ok {
|
||||||
|
panic("no perms for method: " + m.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
perms := meth.Tag.Get("perm")
|
||||||
|
|
||||||
|
fmt.Printf("Perms: %s\n\n", perms)
|
||||||
|
|
||||||
|
if strings.Count(m.InputExample, "\n") > 0 {
|
||||||
|
fmt.Printf("Inputs:\n```json\n%s\n```\n\n", m.InputExample)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Inputs: `%s`\n\n", m.InputExample)
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Count(m.ResponseExample, "\n") > 0 {
|
||||||
|
fmt.Printf("Response:\n```json\n%s\n```\n\n", m.ResponseExample)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Response: `%s`\n\n", m.ResponseExample)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-8
@@ -8,6 +8,7 @@ import (
|
|||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -35,7 +36,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration, carExport bool) {
|
func TestDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration, carExport bool) {
|
||||||
os.Setenv("BELLMAN_NO_GPU", "1")
|
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
n, sn := b(t, 1, oneMiner)
|
n, sn := b(t, 1, oneMiner)
|
||||||
@@ -52,11 +53,11 @@ func TestDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration, carExport
|
|||||||
}
|
}
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
mine := true
|
mine := int64(1)
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
defer close(done)
|
defer close(done)
|
||||||
for mine {
|
for atomic.LoadInt64(&mine) == 1 {
|
||||||
time.Sleep(blocktime)
|
time.Sleep(blocktime)
|
||||||
if err := sn[0].MineOne(ctx, func(bool) {}); err != nil {
|
if err := sn[0].MineOne(ctx, func(bool) {}); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
@@ -66,13 +67,13 @@ func TestDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration, carExport
|
|||||||
|
|
||||||
makeDeal(t, ctx, 6, client, miner, carExport)
|
makeDeal(t, ctx, 6, client, miner, carExport)
|
||||||
|
|
||||||
mine = false
|
atomic.AddInt64(&mine, -1)
|
||||||
fmt.Println("shutting down mining")
|
fmt.Println("shutting down mining")
|
||||||
<-done
|
<-done
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDoubleDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
func TestDoubleDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||||
os.Setenv("BELLMAN_NO_GPU", "1")
|
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
n, sn := b(t, 1, oneMiner)
|
n, sn := b(t, 1, oneMiner)
|
||||||
@@ -89,12 +90,12 @@ func TestDoubleDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
|||||||
}
|
}
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
mine := true
|
mine := int64(1)
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer close(done)
|
defer close(done)
|
||||||
for mine {
|
for atomic.LoadInt64(&mine) == 1 {
|
||||||
time.Sleep(blocktime)
|
time.Sleep(blocktime)
|
||||||
if err := sn[0].MineOne(ctx, func(bool) {}); err != nil {
|
if err := sn[0].MineOne(ctx, func(bool) {}); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
@@ -105,7 +106,7 @@ func TestDoubleDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
|||||||
makeDeal(t, ctx, 6, client, miner, false)
|
makeDeal(t, ctx, 6, client, miner, false)
|
||||||
makeDeal(t, ctx, 7, client, miner, false)
|
makeDeal(t, ctx, 7, client, miner, false)
|
||||||
|
|
||||||
mine = false
|
atomic.AddInt64(&mine, -1)
|
||||||
fmt.Println("shutting down mining")
|
fmt.Println("shutting down mining")
|
||||||
<-done
|
<-done
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-3
@@ -82,7 +82,7 @@ func (ts *testSuite) testMiningReal(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDealMining(t *testing.T, b APIBuilder, blocktime time.Duration, carExport bool) {
|
func TestDealMining(t *testing.T, b APIBuilder, blocktime time.Duration, carExport bool) {
|
||||||
os.Setenv("BELLMAN_NO_GPU", "1")
|
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||||
|
|
||||||
// test making a deal with a fresh miner, and see if it starts to mine
|
// test making a deal with a fresh miner, and see if it starts to mine
|
||||||
|
|
||||||
@@ -126,6 +126,7 @@ func TestDealMining(t *testing.T, b APIBuilder, blocktime time.Duration, carExpo
|
|||||||
minedTwo := make(chan struct{})
|
minedTwo := make(chan struct{})
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
doneMinedTwo := false
|
||||||
defer close(done)
|
defer close(done)
|
||||||
|
|
||||||
prevExpect := 0
|
prevExpect := 0
|
||||||
@@ -175,9 +176,9 @@ func TestDealMining(t *testing.T, b APIBuilder, blocktime time.Duration, carExpo
|
|||||||
time.Sleep(blocktime)
|
time.Sleep(blocktime)
|
||||||
}
|
}
|
||||||
|
|
||||||
if prevExpect == 2 && expect == 2 && minedTwo != nil {
|
if prevExpect == 2 && expect == 2 && !doneMinedTwo {
|
||||||
close(minedTwo)
|
close(minedTwo)
|
||||||
minedTwo = nil
|
doneMinedTwo = true
|
||||||
}
|
}
|
||||||
|
|
||||||
prevExpect = expect
|
prevExpect = expect
|
||||||
|
|||||||
@@ -2,7 +2,11 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||||
|
|
||||||
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
ma "github.com/multiformats/go-multiaddr"
|
ma "github.com/multiformats/go-multiaddr"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -33,3 +37,41 @@ type ObjStat struct {
|
|||||||
Size uint64
|
Size uint64
|
||||||
Links uint64
|
Links uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PubsubScore struct {
|
||||||
|
ID peer.ID
|
||||||
|
Score float64
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
||||||
|
WorkerChangeEpoch abi.ChainEpoch
|
||||||
|
PeerId peer.ID
|
||||||
|
Multiaddrs []abi.Multiaddrs
|
||||||
|
SealProofType abi.RegisteredSealProof
|
||||||
|
SectorSize abi.SectorSize
|
||||||
|
WindowPoStPartitionSectors uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewApiMinerInfo(info miner.MinerInfo) MinerInfo {
|
||||||
|
mi := MinerInfo{
|
||||||
|
Owner: info.Owner,
|
||||||
|
Worker: info.Worker,
|
||||||
|
NewWorker: address.Undef,
|
||||||
|
WorkerChangeEpoch: -1,
|
||||||
|
PeerId: peer.ID(info.PeerId),
|
||||||
|
Multiaddrs: info.Multiaddrs,
|
||||||
|
SealProofType: info.SealProofType,
|
||||||
|
SectorSize: info.SectorSize,
|
||||||
|
WindowPoStPartitionSectors: info.WindowPoStPartitionSectors,
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.PendingWorkerKey != nil {
|
||||||
|
mi.NewWorker = info.PendingWorkerKey.NewWorker
|
||||||
|
mi.WorkerChangeEpoch = info.PendingWorkerKey.EffectiveAt
|
||||||
|
}
|
||||||
|
|
||||||
|
return mi
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func BuiltinBootstrap() ([]peer.AddrInfo, error) {
|
func BuiltinBootstrap() ([]peer.AddrInfo, error) {
|
||||||
|
if DisableBuiltinAssets {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
var out []peer.AddrInfo
|
var out []peer.AddrInfo
|
||||||
|
|
||||||
b := rice.MustFindBox("bootstrap")
|
b := rice.MustFindBox("bootstrap")
|
||||||
@@ -34,3 +38,12 @@ func BuiltinBootstrap() ([]peer.AddrInfo, error) {
|
|||||||
})
|
})
|
||||||
return out, err
|
return out, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DrandBootstrap() ([]peer.AddrInfo, error) {
|
||||||
|
addrs := []string{
|
||||||
|
"/dnsaddr/pl-eu.testnet.drand.sh/",
|
||||||
|
"/dnsaddr/pl-us.testnet.drand.sh/",
|
||||||
|
"/dnsaddr/pl-sin.testnet.drand.sh/",
|
||||||
|
}
|
||||||
|
return addrutil.ParseAddresses(context.TODO(), addrs)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
/dns4/bootstrap-0-sin.fil-test.net/tcp/1347/p2p/12D3KooWKNF7vNFEhnvB45E9mw2B5z6t419W3ziZPLdUDVnLLKGs
|
/dns4/bootstrap-0-sin.fil-test.net/tcp/1347/p2p/12D3KooWPdUquftaQvoQEtEdsRBAhwD6jopbF2oweVTzR59VbHEd
|
||||||
/ip4/86.109.15.57/tcp/1347/p2p/12D3KooWKNF7vNFEhnvB45E9mw2B5z6t419W3ziZPLdUDVnLLKGs
|
/ip4/86.109.15.57/tcp/1347/p2p/12D3KooWPdUquftaQvoQEtEdsRBAhwD6jopbF2oweVTzR59VbHEd
|
||||||
/dns4/bootstrap-0-dfw.fil-test.net/tcp/1347/p2p/12D3KooWECJTm7RUPyGfNbRwm6y2fK4wA7EB8rDJtWsq5AKi7iDr
|
/dns4/bootstrap-0-dfw.fil-test.net/tcp/1347/p2p/12D3KooWQSCkHCzosEyrh8FgYfLejKgEPM5VB6qWzZE3yDAuXn8d
|
||||||
/ip4/139.178.84.45/tcp/1347/p2p/12D3KooWECJTm7RUPyGfNbRwm6y2fK4wA7EB8rDJtWsq5AKi7iDr
|
/ip4/139.178.84.45/tcp/1347/p2p/12D3KooWQSCkHCzosEyrh8FgYfLejKgEPM5VB6qWzZE3yDAuXn8d
|
||||||
/dns4/bootstrap-0-fra.fil-test.net/tcp/1347/p2p/12D3KooWC7MD6m7iNCuDsYtNr7xVtazihyVUizBbhmhEiyMAm9ym
|
/dns4/bootstrap-0-fra.fil-test.net/tcp/1347/p2p/12D3KooWEXN2eQmoyqnNjde9PBAQfQLHN67jcEdWU6JougWrgXJK
|
||||||
/ip4/136.144.49.17/tcp/1347/p2p/12D3KooWC7MD6m7iNCuDsYtNr7xVtazihyVUizBbhmhEiyMAm9ym
|
/ip4/136.144.49.17/tcp/1347/p2p/12D3KooWEXN2eQmoyqnNjde9PBAQfQLHN67jcEdWU6JougWrgXJK
|
||||||
/dns4/bootstrap-1-sin.fil-test.net/tcp/1347/p2p/12D3KooWD8eYqsKcEMFax6EbWN3rjA7qFsxCez2rmN8dWqkzgNaN
|
/dns4/bootstrap-1-sin.fil-test.net/tcp/1347/p2p/12D3KooWLmJkZd33mJhjg5RrpJ6NFep9SNLXWc4uVngV4TXKwzYw
|
||||||
/ip4/86.109.15.55/tcp/1347/p2p/12D3KooWD8eYqsKcEMFax6EbWN3rjA7qFsxCez2rmN8dWqkzgNaN
|
/ip4/86.109.15.123/tcp/1347/p2p/12D3KooWLmJkZd33mJhjg5RrpJ6NFep9SNLXWc4uVngV4TXKwzYw
|
||||||
/dns4/bootstrap-1-dfw.fil-test.net/tcp/1347/p2p/12D3KooWLB3RR8frLAmaK4ntHC2dwrAjyGzQgyUzWxAum1FxyyqD
|
/dns4/bootstrap-1-dfw.fil-test.net/tcp/1347/p2p/12D3KooWGXLHjiz6pTRu7x2pkgTVCoxcCiVxcNLpMnWcJ3JiNEy5
|
||||||
/ip4/139.178.84.41/tcp/1347/p2p/12D3KooWLB3RR8frLAmaK4ntHC2dwrAjyGzQgyUzWxAum1FxyyqD
|
/ip4/139.178.86.3/tcp/1347/p2p/12D3KooWGXLHjiz6pTRu7x2pkgTVCoxcCiVxcNLpMnWcJ3JiNEy5
|
||||||
/dns4/bootstrap-1-fra.fil-test.net/tcp/1347/p2p/12D3KooWGPDJAw3HW4uVU3JEQBfFaZ1kdpg4HvvwRMVpUYbzhsLQ
|
/dns4/bootstrap-1-fra.fil-test.net/tcp/1347/p2p/12D3KooW9szZmKttS9A1FafH3Zc2pxKwwmvCWCGKkRP4KmbhhC4R
|
||||||
/ip4/136.144.49.131/tcp/1347/p2p/12D3KooWGPDJAw3HW4uVU3JEQBfFaZ1kdpg4HvvwRMVpUYbzhsLQ
|
/ip4/136.144.49.131/tcp/1347/p2p/12D3KooW9szZmKttS9A1FafH3Zc2pxKwwmvCWCGKkRP4KmbhhC4R
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package build
|
||||||
|
|
||||||
|
// DisableBuiltinAssets disables the resolution of go.rice boxes that store
|
||||||
|
// built-in assets, such as proof parameters, bootstrap peers, genesis blocks,
|
||||||
|
// etc.
|
||||||
|
//
|
||||||
|
// When this value is set to true, it is expected that the user will
|
||||||
|
// provide any such configurations through the Lotus API itself.
|
||||||
|
//
|
||||||
|
// This is useful when you're using Lotus as a library, such as to orchestrate
|
||||||
|
// test scenarios, or for other purposes where you don't need to use the
|
||||||
|
// defaults shipped with the binary.
|
||||||
|
//
|
||||||
|
// For this flag to be effective, it must be enabled _before_ instantiating Lotus.
|
||||||
|
var DisableBuiltinAssets = false
|
||||||
Binary file not shown.
+4
-5
@@ -12,18 +12,17 @@ import (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
power.ConsensusMinerMinPower = big.NewInt(2048)
|
power.ConsensusMinerMinPower = big.NewInt(2048)
|
||||||
miner.SupportedProofTypes = map[abi.RegisteredProof]struct{}{
|
miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
|
||||||
abi.RegisteredProof_StackedDRG2KiBSeal: {},
|
abi.RegisteredSealProof_StackedDrg2KiBV1: {},
|
||||||
}
|
}
|
||||||
verifreg.MinVerifiedDealSize = big.NewInt(256)
|
verifreg.MinVerifiedDealSize = big.NewInt(256)
|
||||||
|
|
||||||
BuildType |= Build2k
|
BuildType |= Build2k
|
||||||
}
|
}
|
||||||
|
|
||||||
// Seconds
|
const BlockDelaySecs = uint64(2)
|
||||||
const BlockDelay = 2
|
|
||||||
|
|
||||||
const PropagationDelay = 3
|
const PropagationDelaySecs = uint64(3)
|
||||||
|
|
||||||
// SlashablePowerDelay is the number of epochs after ElectionPeriodStart, after
|
// SlashablePowerDelay is the number of epochs after ElectionPeriodStart, after
|
||||||
// which the miner is slashed
|
// which the miner is slashed
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package build
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"github.com/libp2p/go-libp2p-core/protocol"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DefaultSectorSize() abi.SectorSize {
|
||||||
|
szs := make([]abi.SectorSize, 0, len(miner.SupportedProofTypes))
|
||||||
|
for spt := range miner.SupportedProofTypes {
|
||||||
|
ss, err := spt.SectorSize()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
szs = append(szs, ss)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(szs, func(i, j int) bool {
|
||||||
|
return szs[i] < szs[j]
|
||||||
|
})
|
||||||
|
|
||||||
|
return szs[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Core network constants
|
||||||
|
|
||||||
|
func BlocksTopic(netName dtypes.NetworkName) string { return "/fil/blocks/" + string(netName) }
|
||||||
|
func MessagesTopic(netName dtypes.NetworkName) string { return "/fil/msgs/" + string(netName) }
|
||||||
|
func DhtProtocolName(netName dtypes.NetworkName) protocol.ID {
|
||||||
|
return protocol.ID("/fil/kad/" + string(netName))
|
||||||
|
}
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
|
// +build !testground
|
||||||
|
|
||||||
package build
|
package build
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"sort"
|
|
||||||
|
|
||||||
"github.com/libp2p/go-libp2p-core/protocol"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
@@ -13,32 +12,6 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
func DefaultSectorSize() abi.SectorSize {
|
|
||||||
szs := make([]abi.SectorSize, 0, len(miner.SupportedProofTypes))
|
|
||||||
for spt := range miner.SupportedProofTypes {
|
|
||||||
ss, err := spt.SectorSize()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
szs = append(szs, ss)
|
|
||||||
}
|
|
||||||
|
|
||||||
sort.Slice(szs, func(i, j int) bool {
|
|
||||||
return szs[i] < szs[j]
|
|
||||||
})
|
|
||||||
|
|
||||||
return szs[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Core network constants
|
|
||||||
|
|
||||||
func BlocksTopic(netName dtypes.NetworkName) string { return "/fil/blocks/" + string(netName) }
|
|
||||||
func MessagesTopic(netName dtypes.NetworkName) string { return "/fil/msgs/" + string(netName) }
|
|
||||||
func DhtProtocolName(netName dtypes.NetworkName) protocol.ID {
|
|
||||||
return protocol.ID("/fil/kad/" + string(netName))
|
|
||||||
}
|
|
||||||
|
|
||||||
// /////
|
// /////
|
||||||
// Storage
|
// Storage
|
||||||
|
|
||||||
@@ -48,8 +21,7 @@ const UnixfsLinksPerLevel = 1024
|
|||||||
// /////
|
// /////
|
||||||
// Consensus / Network
|
// Consensus / Network
|
||||||
|
|
||||||
// Seconds
|
const AllowableClockDriftSecs = uint64(1)
|
||||||
const AllowableClockDrift = 1
|
|
||||||
|
|
||||||
// Epochs
|
// Epochs
|
||||||
const ForkLengthThreshold = Finality
|
const ForkLengthThreshold = Finality
|
||||||
@@ -59,11 +31,12 @@ var BlocksPerEpoch = uint64(builtin.ExpectedLeadersPerEpoch)
|
|||||||
|
|
||||||
// Epochs
|
// Epochs
|
||||||
const Finality = miner.ChainFinalityish
|
const Finality = miner.ChainFinalityish
|
||||||
|
const MessageConfidence = uint64(5)
|
||||||
|
|
||||||
// constants for Weight calculation
|
// constants for Weight calculation
|
||||||
// The ratio of weight contributed by short-term vs long-term factors in a given round
|
// The ratio of weight contributed by short-term vs long-term factors in a given round
|
||||||
const WRatioNum = int64(1)
|
const WRatioNum = int64(1)
|
||||||
const WRatioDen = 2
|
const WRatioDen = uint64(2)
|
||||||
|
|
||||||
// /////
|
// /////
|
||||||
// Proofs
|
// Proofs
|
||||||
@@ -81,25 +54,25 @@ const MaxSealLookback = SealRandomnessLookbackLimit + 2000 // TODO: Get from spe
|
|||||||
// Mining
|
// Mining
|
||||||
|
|
||||||
// Epochs
|
// Epochs
|
||||||
const TicketRandomnessLookback = 1
|
const TicketRandomnessLookback = abi.ChainEpoch(1)
|
||||||
|
|
||||||
const WinningPoStSectorSetLookback = 10
|
const WinningPoStSectorSetLookback = abi.ChainEpoch(10)
|
||||||
|
|
||||||
// /////
|
// /////
|
||||||
// Devnet settings
|
// Devnet settings
|
||||||
|
|
||||||
const TotalFilecoin = 2_000_000_000
|
const TotalFilecoin = uint64(2_000_000_000)
|
||||||
const MiningRewardTotal = 1_400_000_000
|
const MiningRewardTotal = uint64(1_400_000_000)
|
||||||
|
|
||||||
const FilecoinPrecision = 1_000_000_000_000_000_000
|
const FilecoinPrecision = uint64(1_000_000_000_000_000_000)
|
||||||
|
|
||||||
var InitialRewardBalance *big.Int
|
var InitialRewardBalance *big.Int
|
||||||
|
|
||||||
// TODO: Move other important consts here
|
// TODO: Move other important consts here
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
InitialRewardBalance = big.NewInt(MiningRewardTotal)
|
InitialRewardBalance = big.NewInt(int64(MiningRewardTotal))
|
||||||
InitialRewardBalance = InitialRewardBalance.Mul(InitialRewardBalance, big.NewInt(FilecoinPrecision))
|
InitialRewardBalance = InitialRewardBalance.Mul(InitialRewardBalance, big.NewInt(int64(FilecoinPrecision)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sync
|
// Sync
|
||||||
@@ -120,4 +93,11 @@ const VerifSigCacheSize = 32000
|
|||||||
const BlockMessageLimit = 512
|
const BlockMessageLimit = 512
|
||||||
const BlockGasLimit = 100_000_000_000
|
const BlockGasLimit = 100_000_000_000
|
||||||
|
|
||||||
var DrandChain = `{"public_key":"922a2e93828ff83345bae533f5172669a26c02dc76d6bf59c80892e12ab1455c229211886f35bb56af6d5bea981024df","period":25,"genesis_time":1590445175,"hash":"138a324aa6540f93d0dad002aa89454b1bec2b6e948682cde6bd4db40f4b7c9b"}`
|
var DrandConfig = dtypes.DrandConfig{
|
||||||
|
Servers: []string{
|
||||||
|
"https://pl-eu.testnet.drand.sh",
|
||||||
|
"https://pl-us.testnet.drand.sh",
|
||||||
|
"https://pl-sin.testnet.drand.sh",
|
||||||
|
},
|
||||||
|
ChainInfoJSON: `{"public_key":"922a2e93828ff83345bae533f5172669a26c02dc76d6bf59c80892e12ab1455c229211886f35bb56af6d5bea981024df","period":25,"genesis_time":1590445175,"hash":"138a324aa6540f93d0dad002aa89454b1bec2b6e948682cde6bd4db40f4b7c9b"}`,
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
// +build testground
|
||||||
|
|
||||||
|
// This file makes hardcoded parameters (const) configurable as vars.
|
||||||
|
//
|
||||||
|
// Its purpose is to unlock various degrees of flexibility and parametrization
|
||||||
|
// when writing Testground plans for Lotus.
|
||||||
|
//
|
||||||
|
package build
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
UnixfsChunkSize = uint64(1 << 20)
|
||||||
|
UnixfsLinksPerLevel = 1024
|
||||||
|
|
||||||
|
BlocksPerEpoch = uint64(builtin.ExpectedLeadersPerEpoch)
|
||||||
|
BlockMessageLimit = 512
|
||||||
|
BlockGasLimit = int64(100_000_000_000)
|
||||||
|
BlockDelaySecs = uint64(builtin.EpochDurationSeconds)
|
||||||
|
PropagationDelaySecs = uint64(6)
|
||||||
|
|
||||||
|
AllowableClockDriftSecs = uint64(1)
|
||||||
|
|
||||||
|
Finality = miner.ChainFinalityish
|
||||||
|
ForkLengthThreshold = Finality
|
||||||
|
|
||||||
|
SlashablePowerDelay = 20
|
||||||
|
InteractivePoRepConfidence = 6
|
||||||
|
|
||||||
|
MessageConfidence uint64 = 5
|
||||||
|
|
||||||
|
WRatioNum = int64(1)
|
||||||
|
WRatioDen = uint64(2)
|
||||||
|
|
||||||
|
BadBlockCacheSize = 1 << 15
|
||||||
|
BlsSignatureCacheSize = 40000
|
||||||
|
VerifSigCacheSize = 32000
|
||||||
|
|
||||||
|
SealRandomnessLookback = Finality
|
||||||
|
SealRandomnessLookbackLimit = SealRandomnessLookback + 2000
|
||||||
|
MaxSealLookback = SealRandomnessLookbackLimit + 2000
|
||||||
|
|
||||||
|
TicketRandomnessLookback = abi.ChainEpoch(1)
|
||||||
|
WinningPoStSectorSetLookback = abi.ChainEpoch(10)
|
||||||
|
|
||||||
|
TotalFilecoin uint64 = 2_000_000_000
|
||||||
|
MiningRewardTotal uint64 = 1_400_000_000
|
||||||
|
|
||||||
|
FilecoinPrecision uint64 = 1_000_000_000_000_000_000
|
||||||
|
|
||||||
|
InitialRewardBalance = func() *big.Int {
|
||||||
|
v := big.NewInt(int64(MiningRewardTotal))
|
||||||
|
v = v.Mul(v, big.NewInt(int64(FilecoinPrecision)))
|
||||||
|
return v
|
||||||
|
}()
|
||||||
|
|
||||||
|
DrandConfig = dtypes.DrandConfig{
|
||||||
|
Servers: []string{
|
||||||
|
"https://pl-eu.testnet.drand.sh",
|
||||||
|
"https://pl-us.testnet.drand.sh",
|
||||||
|
"https://pl-sin.testnet.drand.sh",
|
||||||
|
},
|
||||||
|
ChainInfoJSON: `{"public_key":"922a2e93828ff83345bae533f5172669a26c02dc76d6bf59c80892e12ab1455c229211886f35bb56af6d5bea981024df","period":25,"genesis_time":1590445175,"hash":"138a324aa6540f93d0dad002aa89454b1bec2b6e948682cde6bd4db40f4b7c9b"}`,
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
// +build !debug
|
// +build !debug
|
||||||
// +build !2k
|
// +build !2k
|
||||||
|
// +build !testground
|
||||||
|
|
||||||
package build
|
package build
|
||||||
|
|
||||||
@@ -12,15 +13,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
power.ConsensusMinerMinPower = big.NewInt(1024 << 20)
|
power.ConsensusMinerMinPower = big.NewInt(1024 << 30)
|
||||||
miner.SupportedProofTypes = map[abi.RegisteredProof]struct{}{
|
miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
|
||||||
abi.RegisteredProof_StackedDRG512MiBSeal: {},
|
abi.RegisteredSealProof_StackedDrg32GiBV1: {},
|
||||||
abi.RegisteredProof_StackedDRG32GiBSeal: {},
|
abi.RegisteredSealProof_StackedDrg64GiBV1: {},
|
||||||
abi.RegisteredProof_StackedDRG64GiBSeal: {},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Seconds
|
const BlockDelaySecs = uint64(builtin.EpochDurationSeconds)
|
||||||
const BlockDelay = builtin.EpochDurationSeconds
|
|
||||||
|
|
||||||
const PropagationDelay = 6
|
const PropagationDelaySecs = uint64(6)
|
||||||
|
|||||||
@@ -1,152 +1,152 @@
|
|||||||
{
|
{
|
||||||
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0170db1f394b35d995252228ee359194b13199d259380541dc529fb0099096b0.params": {
|
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0170db1f394b35d995252228ee359194b13199d259380541dc529fb0099096b0.params": {
|
||||||
"cid": "QmYkygifkXnrnsN4MJsjBFHTQJHx294CyikDgDK8nYxdGh",
|
"cid": "QmeDRyxek34F1H6xJY6AkFdWvPsy5F6dKTrebV3ZtWT4ky",
|
||||||
"digest": "df3f30442a6d6b4192f5071fb17e820c",
|
"digest": "f5827f2d8801c62c831e0f972f6dc8bb",
|
||||||
"sector_size": 2048
|
"sector_size": 2048
|
||||||
},
|
},
|
||||||
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0170db1f394b35d995252228ee359194b13199d259380541dc529fb0099096b0.vk": {
|
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0170db1f394b35d995252228ee359194b13199d259380541dc529fb0099096b0.vk": {
|
||||||
"cid": "QmdXyqbmy2bkJA9Kyhh6z25GrTCq48LwX6c1mxPsm54wi7",
|
"cid": "QmUw1ZmG4BBbX19MsbH3zAEGKUc42iFJc5ZAyomDHeJTsA",
|
||||||
"digest": "0bea3951abf9557a3569f68e52a30c6c",
|
"digest": "398fecdb4b2de445125852bc3c080b35",
|
||||||
"sector_size": 2048
|
"sector_size": 2048
|
||||||
},
|
},
|
||||||
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0cfb4f178bbb71cf2ecfcd42accce558b27199ab4fb59cb78f2483fe21ef36d9.params": {
|
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0cfb4f178bbb71cf2ecfcd42accce558b27199ab4fb59cb78f2483fe21ef36d9.params": {
|
||||||
"cid": "Qmf5XZZtP5VcYTf65MbKjLVabcS6cYMbr2rFShmfJzh5e5",
|
"cid": "QmUeNKp9YZpiAFm81RV5KuxH1FDGJx2DuwcbU2XNSZLLSv",
|
||||||
"digest": "655e6277638edc8c658094f6f0b33d54",
|
"digest": "2b6d2972ac9e862e8134d98fb695b0c5",
|
||||||
"sector_size": 536870912
|
"sector_size": 536870912
|
||||||
},
|
},
|
||||||
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0cfb4f178bbb71cf2ecfcd42accce558b27199ab4fb59cb78f2483fe21ef36d9.vk": {
|
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0cfb4f178bbb71cf2ecfcd42accce558b27199ab4fb59cb78f2483fe21ef36d9.vk": {
|
||||||
"cid": "QmPuhdWnAXBks43emnkqi9FQzyU1gASKyz23zrD27BPGs8",
|
"cid": "QmQaQmTXX995Akd66ggtJY5bNx6Gkxk8P34JTdMMq8393G",
|
||||||
"digest": "57690e3a6a94c3f704802a674b34f36b",
|
"digest": "3688c9eb256b7b17f411dad78d5ef74a",
|
||||||
"sector_size": 536870912
|
"sector_size": 536870912
|
||||||
},
|
},
|
||||||
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-3ea05428c9d11689f23529cde32fd30aabd50f7d2c93657c1d3650bca3e8ea9e.params": {
|
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-3ea05428c9d11689f23529cde32fd30aabd50f7d2c93657c1d3650bca3e8ea9e.params": {
|
||||||
"cid": "QmPNVgTN7N5vDtD5u7ERMTLcvUtrKRBfYVUDr6uW3pKhX7",
|
"cid": "QmfEYTMSkwGJTumQx26iKXGNKiYh3mmAC4SkdybZpJCj5p",
|
||||||
"digest": "3d390654f58e603b896ac70c653f5676",
|
"digest": "09bff16aed893349d94485cfae366a9c",
|
||||||
"sector_size": 2048
|
"sector_size": 2048
|
||||||
},
|
},
|
||||||
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-3ea05428c9d11689f23529cde32fd30aabd50f7d2c93657c1d3650bca3e8ea9e.vk": {
|
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-3ea05428c9d11689f23529cde32fd30aabd50f7d2c93657c1d3650bca3e8ea9e.vk": {
|
||||||
"cid": "Qmbj61Zez7v5xA7nSCnmWbyLYznWJDWeusz7Yg8EcgVdoN",
|
"cid": "QmP4ThPieSUJyRanjibWpT5R5cCMzMAU4j8Y7kBn7CSW1Q",
|
||||||
"digest": "8c170a164743c39576a7f47a1b51e6f3",
|
"digest": "142f2f7e8f1b1779290315cabfd2c803",
|
||||||
"sector_size": 2048
|
"sector_size": 2048
|
||||||
},
|
},
|
||||||
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-50c7368dea9593ed0989e70974d28024efa9d156d585b7eea1be22b2e753f331.params": {
|
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-50c7368dea9593ed0989e70974d28024efa9d156d585b7eea1be22b2e753f331.params": {
|
||||||
"cid": "QmRApb8RZoBK3cqicT7V3ydXg8yVvqPFMPrQNXP33aBihp",
|
"cid": "QmcAixrHsz29DgvtZiMc2kQjvPRvWxYUp36QYmRDZbmREm",
|
||||||
"digest": "b1b58ff9a297b82885e8a7dfb035f83c",
|
"digest": "8f987f64d434365562180b96ec12e299",
|
||||||
"sector_size": 8388608
|
"sector_size": 8388608
|
||||||
},
|
},
|
||||||
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-50c7368dea9593ed0989e70974d28024efa9d156d585b7eea1be22b2e753f331.vk": {
|
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-50c7368dea9593ed0989e70974d28024efa9d156d585b7eea1be22b2e753f331.vk": {
|
||||||
"cid": "QmcytF1dTdqMFoyXi931j1RgmGtLfR9LLLaBznRt1tPQyD",
|
"cid": "QmT4iFnbL6r4txS5PXsiV7NTzbhCxHy54PvdkJJGV2VFXb",
|
||||||
"digest": "1a09e00c641f192f55af3433a028f050",
|
"digest": "94b6c24ac01924f4feeecedd16b5d77d",
|
||||||
"sector_size": 8388608
|
"sector_size": 8388608
|
||||||
},
|
},
|
||||||
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-5294475db5237a2e83c3e52fd6c2b03859a1831d45ed08c4f35dbf9a803165a9.params": {
|
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-5294475db5237a2e83c3e52fd6c2b03859a1831d45ed08c4f35dbf9a803165a9.params": {
|
||||||
"cid": "QmPvr54tWaVeP4WnekivzUAJitTqsQfvikBvAHNEaDNQSw",
|
"cid": "QmbjFst6SFCK1KsTQrfwPdxf3VTNa1raed574tEZZ9PoyQ",
|
||||||
"digest": "9380e41368ed4083dbc922b290d3b786",
|
"digest": "2c245fe8179839dd6c6cdea207c67ae8",
|
||||||
"sector_size": 8388608
|
"sector_size": 8388608
|
||||||
},
|
},
|
||||||
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-5294475db5237a2e83c3e52fd6c2b03859a1831d45ed08c4f35dbf9a803165a9.vk": {
|
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-5294475db5237a2e83c3e52fd6c2b03859a1831d45ed08c4f35dbf9a803165a9.vk": {
|
||||||
"cid": "QmXyVLVDRCcxA9SjT7PeK8HFtyxZ2ZH3SHa8KoGLw8VGJt",
|
"cid": "QmQJKmvZN1a5cQ1Nw6CDyXs3nuRPzvyU5NvCFMUL2BfcZC",
|
||||||
"digest": "f0731a7e20f90704bd38fc5d27882f6d",
|
"digest": "56ae47bfda53bb8d22981ed8d8d27d72",
|
||||||
"sector_size": 8388608
|
"sector_size": 8388608
|
||||||
},
|
},
|
||||||
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-7d739b8cf60f1b0709eeebee7730e297683552e4b69cab6984ec0285663c5781.params": {
|
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-7d739b8cf60f1b0709eeebee7730e297683552e4b69cab6984ec0285663c5781.params": {
|
||||||
"cid": "Qmf5f6ko3dqj7qauzXpZqxM9B2x2sL977K6gE2ppNwuJPv",
|
"cid": "QmQCABxeTpdvXTyjDyk7nPBxkQzCh7MXfGztWnSXEPKMLW",
|
||||||
"digest": "273ebb8c896326b7c292bee8b775fd38",
|
"digest": "7e6b2eb5ecbb11ac651ad66ebbb2075a",
|
||||||
"sector_size": 536870912
|
"sector_size": 536870912
|
||||||
},
|
},
|
||||||
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-7d739b8cf60f1b0709eeebee7730e297683552e4b69cab6984ec0285663c5781.vk": {
|
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-7d739b8cf60f1b0709eeebee7730e297683552e4b69cab6984ec0285663c5781.vk": {
|
||||||
"cid": "QmfP3MQe8koW63n5MkDENENVHxib78MJYYyZvbneCsuze8",
|
"cid": "QmPBweyugh5Sx4umk8ULhgEGbjY8xmWLfU6M7EMpc8Mad6",
|
||||||
"digest": "3dd94da9da64e51b3445bc528d84e76d",
|
"digest": "94a8d9e25a9ab9674d339833664eba25",
|
||||||
"sector_size": 536870912
|
"sector_size": 536870912
|
||||||
},
|
},
|
||||||
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-0377ded656c6f524f1618760bffe4e0a1c51d5a70c4509eedae8a27555733edc.params": {
|
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-0377ded656c6f524f1618760bffe4e0a1c51d5a70c4509eedae8a27555733edc.params": {
|
||||||
"cid": "QmYEeeCE8uT2bsVkxcqqUYeMmMEbe6rfmo8wQCv7jFHqqm",
|
"cid": "QmY5yax1E9KymBnCeHksE9Zi8NieZbmwcpoDGoabkeeb9h",
|
||||||
"digest": "c947f2021304ed43b7216f7a8436e294",
|
"digest": "c909ea9e3fe25ab9b391a64593afdbba",
|
||||||
"sector_size": 34359738368
|
"sector_size": 34359738368
|
||||||
},
|
},
|
||||||
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-0377ded656c6f524f1618760bffe4e0a1c51d5a70c4509eedae8a27555733edc.vk": {
|
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-0377ded656c6f524f1618760bffe4e0a1c51d5a70c4509eedae8a27555733edc.vk": {
|
||||||
"cid": "QmXB63ExriFjB4ywWnXTnFwCcLFfCeEP3h15qtL5i7F4aX",
|
"cid": "QmXnPo4yH5mwMguwrvqgRfduSttbmPrXtbBfbwU21wQWHt",
|
||||||
"digest": "ab20d7b253e7e9a0d2ccdf7599ec8ec3",
|
"digest": "caf900461e988bbf86dbcaca087b7864",
|
||||||
"sector_size": 34359738368
|
"sector_size": 34359738368
|
||||||
},
|
},
|
||||||
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-559e581f022bb4e4ec6e719e563bf0e026ad6de42e56c18714a2c692b1b88d7e.params": {
|
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-559e581f022bb4e4ec6e719e563bf0e026ad6de42e56c18714a2c692b1b88d7e.params": {
|
||||||
"cid": "QmW5Yxg3L1NSzuQVcRMHMbG3uvVoi4dTLzVaDpnEUPQpnA",
|
"cid": "QmZtzzPWwmZEgR7MSMvXRbt9KVK8k4XZ5RLWHybHJW9SdE",
|
||||||
"digest": "079ba19645828ae42b22b0e3f4866e8d",
|
"digest": "a2844f0703f186d143a06146a04577d8",
|
||||||
"sector_size": 34359738368
|
"sector_size": 34359738368
|
||||||
},
|
},
|
||||||
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-559e581f022bb4e4ec6e719e563bf0e026ad6de42e56c18714a2c692b1b88d7e.vk": {
|
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-559e581f022bb4e4ec6e719e563bf0e026ad6de42e56c18714a2c692b1b88d7e.vk": {
|
||||||
"cid": "QmQzZ5dJ11tcSBees38WX41tZLXS9BqpEti253m5QcnTNs",
|
"cid": "QmWxEA7EdQCUJTzjNpxg5XTF45D2uVyYnN1QRUb5TRYU8M",
|
||||||
"digest": "c76125a50a7de315165de359b5174ae4",
|
"digest": "2306247a1e616dbe07f01b88196c2044",
|
||||||
"sector_size": 34359738368
|
"sector_size": 34359738368
|
||||||
},
|
},
|
||||||
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-2627e4006b67f99cef990c0a47d5426cb7ab0a0ad58fc1061547bf2d28b09def.params": {
|
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-2627e4006b67f99cef990c0a47d5426cb7ab0a0ad58fc1061547bf2d28b09def.params": {
|
||||||
"cid": "QmNk3wga1tS53FUu1QnkK8ehWA2cqpCnSEAPv3KLxdJxNa",
|
"cid": "QmP676KwuvyF9Y64uJnXvLtvD1xcuWQ6wD23RzYtQ6dd4f",
|
||||||
"digest": "421e4790c0b80e0107a7ff67acf14084",
|
"digest": "215b1c667a4f46a1d0178338df568615",
|
||||||
"sector_size": 68719476736
|
"sector_size": 68719476736
|
||||||
},
|
},
|
||||||
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-2627e4006b67f99cef990c0a47d5426cb7ab0a0ad58fc1061547bf2d28b09def.vk": {
|
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-2627e4006b67f99cef990c0a47d5426cb7ab0a0ad58fc1061547bf2d28b09def.vk": {
|
||||||
"cid": "QmVQCHGsrUtbn9RjHs1e6GXfeXDW5m9w4ge48PSX3Z2as2",
|
"cid": "QmPvPwbJtcSGyqB1rQJhSF5yvFbX9ZBSsHVej5F8JUyHUJ",
|
||||||
"digest": "8b60e9cc1470a6729c687d6cf0a1f79c",
|
"digest": "0c9c423b28b1455fcbc329a1045fd4dd",
|
||||||
"sector_size": 68719476736
|
"sector_size": 68719476736
|
||||||
},
|
},
|
||||||
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-b62098629d07946e9028127e70295ed996fe3ed25b0f9f88eb610a0ab4385a3c.params": {
|
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-b62098629d07946e9028127e70295ed996fe3ed25b0f9f88eb610a0ab4385a3c.params": {
|
||||||
"cid": "QmTL3VvydaMFWKvE5VzxjgKsJYgL9JMM4JVYNtQxdj9JK1",
|
"cid": "QmUxPQfvckzm1t6MFRdDZ1fDK5UJzAjK7pTZ97cwyachdr",
|
||||||
"digest": "2685f31124b22ea6b2857e5a5e87ffa3",
|
"digest": "965132f51ae445b0e6d32692b7561995",
|
||||||
"sector_size": 68719476736
|
"sector_size": 68719476736
|
||||||
},
|
},
|
||||||
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-b62098629d07946e9028127e70295ed996fe3ed25b0f9f88eb610a0ab4385a3c.vk": {
|
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-b62098629d07946e9028127e70295ed996fe3ed25b0f9f88eb610a0ab4385a3c.vk": {
|
||||||
"cid": "QmSVWbLqQYbUbbJyfsRMzEib2rfSqMtnPks1Nw22omcBQm",
|
"cid": "QmTxq2EBnQWb5R8tS4MHdchj4vNfLYGoSXxwJFvs5xgW4K",
|
||||||
"digest": "efe703cd2839597c7ca5c2a906b74296",
|
"digest": "fc8c3d26e0e56373ad96cb41520d55a6",
|
||||||
"sector_size": 68719476736
|
"sector_size": 68719476736
|
||||||
},
|
},
|
||||||
"v26-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-032d3138d22506ec0082ed72b2dcba18df18477904e35bafee82b3793b06832f.params": {
|
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-032d3138d22506ec0082ed72b2dcba18df18477904e35bafee82b3793b06832f.params": {
|
||||||
"cid": "QmU9dH31nZZUJnsogR4Ld4ySUcH6wm2RgmGiujwnqtbU6k",
|
"cid": "QmRjgZHERgqGoRagR788Kh6ybi26csVYa8mqbqhmZm57Jx",
|
||||||
"digest": "fcef8e87ae2afd7a28aae44347b804cf",
|
"digest": "cfc7b0897d1eee48c586f7beb89e67f7",
|
||||||
"sector_size": 2048
|
"sector_size": 2048
|
||||||
},
|
},
|
||||||
"v26-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-032d3138d22506ec0082ed72b2dcba18df18477904e35bafee82b3793b06832f.vk": {
|
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-032d3138d22506ec0082ed72b2dcba18df18477904e35bafee82b3793b06832f.vk": {
|
||||||
"cid": "QmdJ15DMGPooye5NaPcRfXUdHUDibcN7hKjbmTGuu1K4AQ",
|
"cid": "QmNjvnvFP7KgovHUddULoB19fBHT81iz7NcUbzEHZUUPsm",
|
||||||
"digest": "2ee2b3518229680db15161d4f582af37",
|
"digest": "fb59bd061c987eac7068008c44de346b",
|
||||||
"sector_size": 2048
|
"sector_size": 2048
|
||||||
},
|
},
|
||||||
"v26-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-6babf46ce344ae495d558e7770a585b2382d54f225af8ed0397b8be7c3fcd472.params": {
|
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-6babf46ce344ae495d558e7770a585b2382d54f225af8ed0397b8be7c3fcd472.params": {
|
||||||
"cid": "QmZgtxcY3tMXXQxZTA7ZTUDXLVUnfxNcerXgeW4gG2NnfP",
|
"cid": "QmTpRPBA4dt8fgGpcVzi4L1KA1U2eBHCE8WVmS2GUygMvT",
|
||||||
"digest": "3273c7135cb75684248b475781b738ee",
|
"digest": "36d465915b0afbf96bd08e7915e00952",
|
||||||
"sector_size": 536870912
|
"sector_size": 536870912
|
||||||
},
|
},
|
||||||
"v26-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-6babf46ce344ae495d558e7770a585b2382d54f225af8ed0397b8be7c3fcd472.vk": {
|
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-6babf46ce344ae495d558e7770a585b2382d54f225af8ed0397b8be7c3fcd472.vk": {
|
||||||
"cid": "QmSS6ZkAV2aGZcgKgdPpEEgihXF1ryZX8PSAZDWSoeL1d4",
|
"cid": "QmRzDyVfQCLsxspoVsed5bcQRsG6KiktngJfcNBL3TJPZe",
|
||||||
"digest": "1519b5f61d9044a59f2bdc57537c094b",
|
"digest": "99d16df0eb6a7e227a4f4570c4f6b6f1",
|
||||||
"sector_size": 536870912
|
"sector_size": 536870912
|
||||||
},
|
},
|
||||||
"v26-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-ecd683648512ab1765faa2a5f14bab48f676e633467f0aa8aad4b55dcb0652bb.params": {
|
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-ecd683648512ab1765faa2a5f14bab48f676e633467f0aa8aad4b55dcb0652bb.params": {
|
||||||
"cid": "QmQBGXeiNn6hVwbR6qFarQqiNGDdKk4h9ucfyvcXyfYz2N",
|
"cid": "QmV8ZjTSGzDUWmFvsq9NSyPBR7eDDUcvCPNgj2yE7HMAFu",
|
||||||
"digest": "7d5f896f435c38e93bcda6dd168d860b",
|
"digest": "34f3ddf1d1c9f41c0cd73b91e8b4bc27",
|
||||||
"sector_size": 8388608
|
"sector_size": 8388608
|
||||||
},
|
},
|
||||||
"v26-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-ecd683648512ab1765faa2a5f14bab48f676e633467f0aa8aad4b55dcb0652bb.vk": {
|
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-ecd683648512ab1765faa2a5f14bab48f676e633467f0aa8aad4b55dcb0652bb.vk": {
|
||||||
"cid": "QmPrZgBVGMckEAeu5eSJnLmiAwcPQjKjZe5ir6VaQ5AxKs",
|
"cid": "QmTa3VbjTiqJWU6r4WKayaQrUaaBsrpp5UDqYvPDd2C5hs",
|
||||||
"digest": "fe6d2de44580a0db5a4934688899b92f",
|
"digest": "ec62d59651daa5631d3d1e9c782dd940",
|
||||||
"sector_size": 8388608
|
"sector_size": 8388608
|
||||||
},
|
},
|
||||||
"v26-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-0-sha256_hasher-82a357d2f2ca81dc61bb45f4a762807aedee1b0a53fd6c4e77b46a01bfef7820.params": {
|
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-0-sha256_hasher-82a357d2f2ca81dc61bb45f4a762807aedee1b0a53fd6c4e77b46a01bfef7820.params": {
|
||||||
"cid": "QmZL2cq45XJn5BFzagAZwgFmLrcM1W6CXoiEF9C5j5tjEF",
|
"cid": "Qmf8ngfArxrv9tFWDqBcNegdBMymvuakwyHKd1pbW3pbsb",
|
||||||
"digest": "acdfed9f0512bc85a01a9fb871d475d5",
|
"digest": "a16d6f4c6424fb280236739f84b24f97",
|
||||||
"sector_size": 34359738368
|
"sector_size": 34359738368
|
||||||
},
|
},
|
||||||
"v26-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-0-sha256_hasher-82a357d2f2ca81dc61bb45f4a762807aedee1b0a53fd6c4e77b46a01bfef7820.vk": {
|
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-0-sha256_hasher-82a357d2f2ca81dc61bb45f4a762807aedee1b0a53fd6c4e77b46a01bfef7820.vk": {
|
||||||
"cid": "QmQ4zB7nNa1tDYNifBkExRnZtwtxZw775iaqvVsZyRi6Q2",
|
"cid": "QmfQgVFerArJ6Jupwyc9tKjLD9n1J9ajLHBdpY465tRM7M",
|
||||||
"digest": "524a2f3e9d6826593caebc41bb545c40",
|
"digest": "7a139d82b8a02e35279d657e197f5c1f",
|
||||||
"sector_size": 34359738368
|
"sector_size": 34359738368
|
||||||
},
|
},
|
||||||
"v26-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-2-sha256_hasher-96f1b4a04c5c51e4759bbf224bbc2ef5a42c7100f16ec0637123f16a845ddfb2.params": {
|
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-2-sha256_hasher-96f1b4a04c5c51e4759bbf224bbc2ef5a42c7100f16ec0637123f16a845ddfb2.params": {
|
||||||
"cid": "QmY7DitNKXFeLQt9QoVQkfjM1EvRnprqUVxjmkTXkHDNka",
|
"cid": "QmfDha8271nXJn14Aq3qQeghjMBWbs6HNSGa6VuzCVk4TW",
|
||||||
"digest": "f27271c0537ba65ade2ec045f8fbd069",
|
"digest": "5d3cd3f107a3bea8a96d1189efd2965c",
|
||||||
"sector_size": 68719476736
|
"sector_size": 68719476736
|
||||||
},
|
},
|
||||||
"v26-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-2-sha256_hasher-96f1b4a04c5c51e4759bbf224bbc2ef5a42c7100f16ec0637123f16a845ddfb2.vk": {
|
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-2-sha256_hasher-96f1b4a04c5c51e4759bbf224bbc2ef5a42c7100f16ec0637123f16a845ddfb2.vk": {
|
||||||
"cid": "QmUJsvoCuQ4LszPmeRVAkMYb5qY95ctz3UXKhu8xLzyFKo",
|
"cid": "QmRVtTtiFzHJTHurYzaCvetGAchux9cktixT4aGHthN6Zt",
|
||||||
"digest": "576b292938c6c9d0a0e721bd867a543b",
|
"digest": "62c366405404e60f171e661492740b1c",
|
||||||
"sector_size": 68719476736
|
"sector_size": 68719476736
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+3
-3
@@ -25,7 +25,7 @@ func buildType() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// BuildVersion is the local build version, set by build system
|
// BuildVersion is the local build version, set by build system
|
||||||
const BuildVersion = "0.4.0"
|
const BuildVersion = "0.4.1"
|
||||||
|
|
||||||
func UserVersion() string {
|
func UserVersion() string {
|
||||||
return BuildVersion + buildType() + CurrentCommit
|
return BuildVersion + buildType() + CurrentCommit
|
||||||
@@ -53,9 +53,9 @@ func (ve Version) EqMajorMinor(v2 Version) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// APIVersion is a semver version of the rpc api exposed
|
// APIVersion is a semver version of the rpc api exposed
|
||||||
var APIVersion Version = newVer(0, 3, 0)
|
var APIVersion Version = newVer(0, 5, 0)
|
||||||
|
|
||||||
//nolint:varcheck
|
//nolint:varcheck,deadcode
|
||||||
const (
|
const (
|
||||||
majorMask = 0xff0000
|
majorMask = 0xff0000
|
||||||
minorMask = 0xffff00
|
minorMask = 0xffff00
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ type Response struct {
|
|||||||
Err error
|
Err error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RandomBeacon represents a system that provides randomness to Lotus.
|
||||||
|
// Other components interrogate the RandomBeacon to acquire randomness that's
|
||||||
|
// valid for a specific chain epoch. Also to verify beacon entries that have
|
||||||
|
// been posted on chain.
|
||||||
type RandomBeacon interface {
|
type RandomBeacon interface {
|
||||||
Entry(context.Context, uint64) <-chan Response
|
Entry(context.Context, uint64) <-chan Response
|
||||||
VerifyEntry(types.BeaconEntry, types.BeaconEntry) error
|
VerifyEntry(types.BeaconEntry, types.BeaconEntry) error
|
||||||
|
|||||||
+31
-31
@@ -8,8 +8,9 @@ import (
|
|||||||
|
|
||||||
dchain "github.com/drand/drand/chain"
|
dchain "github.com/drand/drand/chain"
|
||||||
dclient "github.com/drand/drand/client"
|
dclient "github.com/drand/drand/client"
|
||||||
gclient "github.com/drand/drand/cmd/relay-gossip/client"
|
hclient "github.com/drand/drand/client/http"
|
||||||
dlog "github.com/drand/drand/log"
|
dlog "github.com/drand/drand/log"
|
||||||
|
gclient "github.com/drand/drand/lp2p/client"
|
||||||
"github.com/drand/kyber"
|
"github.com/drand/kyber"
|
||||||
kzap "github.com/go-kit/kit/log/zap"
|
kzap "github.com/go-kit/kit/log/zap"
|
||||||
"go.uber.org/zap/zapcore"
|
"go.uber.org/zap/zapcore"
|
||||||
@@ -18,31 +19,15 @@ import (
|
|||||||
logging "github.com/ipfs/go-log"
|
logging "github.com/ipfs/go-log"
|
||||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/beacon"
|
"github.com/filecoin-project/lotus/chain/beacon"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
var log = logging.Logger("drand")
|
var log = logging.Logger("drand")
|
||||||
|
|
||||||
var drandServers = []string{
|
|
||||||
"https://pl-eu.testnet.drand.sh",
|
|
||||||
"https://pl-us.testnet.drand.sh",
|
|
||||||
"https://pl-sin.testnet.drand.sh",
|
|
||||||
}
|
|
||||||
|
|
||||||
var drandChain *dchain.Info
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
|
|
||||||
var err error
|
|
||||||
drandChain, err = dchain.InfoFromJSON(bytes.NewReader([]byte(build.DrandChain)))
|
|
||||||
if err != nil {
|
|
||||||
panic("could not unmarshal chain info: " + err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type drandPeer struct {
|
type drandPeer struct {
|
||||||
addr string
|
addr string
|
||||||
tls bool
|
tls bool
|
||||||
@@ -56,6 +41,13 @@ func (dp *drandPeer) IsTLS() bool {
|
|||||||
return dp.tls
|
return dp.tls
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DrandBeacon connects Lotus with a drand network in order to provide
|
||||||
|
// randomness to the system in a way that's aligned with Filecoin rounds/epochs.
|
||||||
|
//
|
||||||
|
// We connect to drand peers via their public HTTP endpoints. The peers are
|
||||||
|
// enumerated in the drandServers variable.
|
||||||
|
//
|
||||||
|
// The root trust for the Drand chain is configured from build.DrandChain.
|
||||||
type DrandBeacon struct {
|
type DrandBeacon struct {
|
||||||
client dclient.Client
|
client dclient.Client
|
||||||
|
|
||||||
@@ -72,18 +64,34 @@ type DrandBeacon struct {
|
|||||||
localCache map[uint64]types.BeaconEntry
|
localCache map[uint64]types.BeaconEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDrandBeacon(genesisTs, interval uint64, ps *pubsub.PubSub) (*DrandBeacon, error) {
|
func NewDrandBeacon(genesisTs, interval uint64, ps *pubsub.PubSub, config dtypes.DrandConfig) (*DrandBeacon, error) {
|
||||||
if genesisTs == 0 {
|
if genesisTs == 0 {
|
||||||
panic("what are you doing this cant be zero")
|
panic("what are you doing this cant be zero")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
drandChain, err := dchain.InfoFromJSON(bytes.NewReader([]byte(config.ChainInfoJSON)))
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("unable to unmarshal drand chain info: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
dlogger := dlog.NewKitLoggerFrom(kzap.NewZapSugarLogger(
|
dlogger := dlog.NewKitLoggerFrom(kzap.NewZapSugarLogger(
|
||||||
log.SugaredLogger.Desugar(), zapcore.InfoLevel))
|
log.SugaredLogger.Desugar(), zapcore.InfoLevel))
|
||||||
|
|
||||||
|
var clients []dclient.Client
|
||||||
|
for _, url := range config.Servers {
|
||||||
|
hc, err := hclient.NewWithInfo(url, drandChain, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("could not create http drand client: %w", err)
|
||||||
|
}
|
||||||
|
clients = append(clients, hc)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
opts := []dclient.Option{
|
opts := []dclient.Option{
|
||||||
dclient.WithChainInfo(drandChain),
|
dclient.WithChainInfo(drandChain),
|
||||||
dclient.WithHTTPEndpoints(drandServers),
|
|
||||||
dclient.WithCacheSize(1024),
|
dclient.WithCacheSize(1024),
|
||||||
dclient.WithLogger(dlogger),
|
dclient.WithLogger(dlogger),
|
||||||
|
dclient.WithAutoWatch(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if ps != nil {
|
if ps != nil {
|
||||||
@@ -92,19 +100,11 @@ func NewDrandBeacon(genesisTs, interval uint64, ps *pubsub.PubSub) (*DrandBeacon
|
|||||||
log.Info("drand beacon without pubsub")
|
log.Info("drand beacon without pubsub")
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := dclient.New(opts...)
|
client, err := dclient.Wrap(clients, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("creating drand client")
|
return nil, xerrors.Errorf("creating drand client")
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
|
||||||
// Explicitly Watch until that is fixed in drand
|
|
||||||
ch := client.Watch(context.Background())
|
|
||||||
for range ch {
|
|
||||||
}
|
|
||||||
log.Error("dranch Watch bork")
|
|
||||||
}()
|
|
||||||
|
|
||||||
db := &DrandBeacon{
|
db := &DrandBeacon{
|
||||||
client: client,
|
client: client,
|
||||||
localCache: make(map[uint64]types.BeaconEntry),
|
localCache: make(map[uint64]types.BeaconEntry),
|
||||||
|
|||||||
@@ -5,12 +5,15 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
dchain "github.com/drand/drand/chain"
|
dchain "github.com/drand/drand/chain"
|
||||||
dclient "github.com/drand/drand/client"
|
hclient "github.com/drand/drand/client/http"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/build"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPrintGroupInfo(t *testing.T) {
|
func TestPrintGroupInfo(t *testing.T) {
|
||||||
c, err := dclient.NewHTTPClient(drandServers[0], nil, nil)
|
server := build.DrandConfig.Servers[0]
|
||||||
|
c, err := hclient.New(server, nil, nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
cg := c.(interface {
|
cg := c.(interface {
|
||||||
FetchChainInfo(groupHash []byte) (*dchain.Info, error)
|
FetchChainInfo(groupHash []byte) (*dchain.Info, error)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
cborutil "github.com/filecoin-project/go-cbor-util"
|
cborutil "github.com/filecoin-project/go-cbor-util"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/store"
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
|
||||||
@@ -27,6 +28,24 @@ const BlockSyncProtocolID = "/fil/sync/blk/0.0.1"
|
|||||||
|
|
||||||
const BlockSyncMaxRequestLength = 800
|
const BlockSyncMaxRequestLength = 800
|
||||||
|
|
||||||
|
// BlockSyncService is the component that services BlockSync requests from
|
||||||
|
// peers.
|
||||||
|
//
|
||||||
|
// BlockSync is the basic chain synchronization protocol of Filecoin. BlockSync
|
||||||
|
// is an RPC-oriented protocol, with a single operation to request blocks.
|
||||||
|
//
|
||||||
|
// A request contains a start anchor block (referred to with a CID), and a
|
||||||
|
// amount of blocks requested beyond the anchor (including the anchor itself).
|
||||||
|
//
|
||||||
|
// A client can also pass options, encoded as a 64-bit bitfield. Lotus supports
|
||||||
|
// two options at the moment:
|
||||||
|
//
|
||||||
|
// - include block contents
|
||||||
|
// - include block messages
|
||||||
|
//
|
||||||
|
// The response will include a status code, an optional message, and the
|
||||||
|
// response payload in case of success. The payload is a slice of serialized
|
||||||
|
// tipsets.
|
||||||
type BlockSyncService struct {
|
type BlockSyncService struct {
|
||||||
cs *store.ChainStore
|
cs *store.ChainStore
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,6 +64,11 @@ func (bs *BlockSync) processStatus(req *BlockSyncRequest, res *BlockSyncResponse
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetBlocks fetches count blocks from the network, from the provided tipset
|
||||||
|
// *backwards*, returning as many tipsets as count.
|
||||||
|
//
|
||||||
|
// {hint/usage}: This is used by the Syncer during normal chain syncing and when
|
||||||
|
// resolving forks.
|
||||||
func (bs *BlockSync) GetBlocks(ctx context.Context, tsk types.TipSetKey, count int) ([]*types.TipSet, error) {
|
func (bs *BlockSync) GetBlocks(ctx context.Context, tsk types.TipSetKey, count int) ([]*types.TipSet, error) {
|
||||||
ctx, span := trace.StartSpan(ctx, "bsync.GetBlocks")
|
ctx, span := trace.StartSpan(ctx, "bsync.GetBlocks")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
@@ -80,7 +85,9 @@ func (bs *BlockSync) GetBlocks(ctx context.Context, tsk types.TipSetKey, count i
|
|||||||
Options: BSOptBlocks,
|
Options: BSOptBlocks,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this peerset is sorted by latency and failure counting.
|
||||||
peers := bs.getPeers()
|
peers := bs.getPeers()
|
||||||
|
|
||||||
// randomize the first few peers so we don't always pick the same peer
|
// randomize the first few peers so we don't always pick the same peer
|
||||||
shufflePrefix(peers)
|
shufflePrefix(peers)
|
||||||
|
|
||||||
@@ -356,6 +363,7 @@ func (bs *BlockSync) RemovePeer(p peer.ID) {
|
|||||||
bs.syncPeers.removePeer(p)
|
bs.syncPeers.removePeer(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getPeers returns a preference-sorted set of peers to query.
|
||||||
func (bs *BlockSync) getPeers() []peer.ID {
|
func (bs *BlockSync) getPeers() []peer.ID {
|
||||||
return bs.syncPeers.prefSortedPeers()
|
return bs.syncPeers.prefSortedPeers()
|
||||||
}
|
}
|
||||||
@@ -561,26 +569,30 @@ func (bpt *bsPeerTracker) logSuccess(p peer.ID, dur time.Duration) {
|
|||||||
bpt.lk.Lock()
|
bpt.lk.Lock()
|
||||||
defer bpt.lk.Unlock()
|
defer bpt.lk.Unlock()
|
||||||
|
|
||||||
if pi, ok := bpt.peers[p]; !ok {
|
var pi *peerStats
|
||||||
|
var ok bool
|
||||||
|
if pi, ok = bpt.peers[p]; !ok {
|
||||||
log.Warnw("log success called on peer not in tracker", "peerid", p.String())
|
log.Warnw("log success called on peer not in tracker", "peerid", p.String())
|
||||||
return
|
return
|
||||||
} else {
|
|
||||||
pi.successes++
|
|
||||||
|
|
||||||
logTime(pi, dur)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pi.successes++
|
||||||
|
logTime(pi, dur)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bpt *bsPeerTracker) logFailure(p peer.ID, dur time.Duration) {
|
func (bpt *bsPeerTracker) logFailure(p peer.ID, dur time.Duration) {
|
||||||
bpt.lk.Lock()
|
bpt.lk.Lock()
|
||||||
defer bpt.lk.Unlock()
|
defer bpt.lk.Unlock()
|
||||||
if pi, ok := bpt.peers[p]; !ok {
|
|
||||||
|
var pi *peerStats
|
||||||
|
var ok bool
|
||||||
|
if pi, ok = bpt.peers[p]; !ok {
|
||||||
log.Warn("log failure called on peer not in tracker", "peerid", p.String())
|
log.Warn("log failure called on peer not in tracker", "peerid", p.String())
|
||||||
return
|
return
|
||||||
} else {
|
|
||||||
pi.failures++
|
|
||||||
logTime(pi, dur)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pi.failures++
|
||||||
|
logTime(pi, dur)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bpt *bsPeerTracker) removePeer(p peer.ID) {
|
func (bpt *bsPeerTracker) removePeer(p peer.ID) {
|
||||||
|
|||||||
+8
-19
@@ -19,7 +19,7 @@ import (
|
|||||||
|
|
||||||
var log = logging.Logger("events")
|
var log = logging.Logger("events")
|
||||||
|
|
||||||
// `curH`-`ts.Height` = `confidence`
|
// HeightHandler `curH`-`ts.Height` = `confidence`
|
||||||
type HeightHandler func(ctx context.Context, ts *types.TipSet, curH abi.ChainEpoch) error
|
type HeightHandler func(ctx context.Context, ts *types.TipSet, curH abi.ChainEpoch) error
|
||||||
type RevertHandler func(ctx context.Context, ts *types.TipSet) error
|
type RevertHandler func(ctx context.Context, ts *types.TipSet) error
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ type heightHandler struct {
|
|||||||
revert RevertHandler
|
revert RevertHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
type eventApi interface {
|
type eventAPI interface {
|
||||||
ChainNotify(context.Context) (<-chan []*api.HeadChange, error)
|
ChainNotify(context.Context) (<-chan []*api.HeadChange, error)
|
||||||
ChainGetBlockMessages(context.Context, cid.Cid) (*api.BlockMessages, error)
|
ChainGetBlockMessages(context.Context, cid.Cid) (*api.BlockMessages, error)
|
||||||
ChainGetTipSetByHeight(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error)
|
ChainGetTipSetByHeight(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error)
|
||||||
@@ -42,7 +42,7 @@ type eventApi interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Events struct {
|
type Events struct {
|
||||||
api eventApi
|
api eventAPI
|
||||||
|
|
||||||
tsc *tipSetCache
|
tsc *tipSetCache
|
||||||
lk sync.Mutex
|
lk sync.Mutex
|
||||||
@@ -51,10 +51,10 @@ type Events struct {
|
|||||||
readyOnce sync.Once
|
readyOnce sync.Once
|
||||||
|
|
||||||
heightEvents
|
heightEvents
|
||||||
calledEvents
|
*hcEvents
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEvents(ctx context.Context, api eventApi) *Events {
|
func NewEvents(ctx context.Context, api eventAPI) *Events {
|
||||||
gcConfidence := 2 * build.ForkLengthThreshold
|
gcConfidence := 2 * build.ForkLengthThreshold
|
||||||
|
|
||||||
tsc := newTSCache(gcConfidence, api.ChainGetTipSetByHeight)
|
tsc := newTSCache(gcConfidence, api.ChainGetTipSetByHeight)
|
||||||
@@ -74,18 +74,7 @@ func NewEvents(ctx context.Context, api eventApi) *Events {
|
|||||||
htHeights: map[abi.ChainEpoch][]uint64{},
|
htHeights: map[abi.ChainEpoch][]uint64{},
|
||||||
},
|
},
|
||||||
|
|
||||||
calledEvents: calledEvents{
|
hcEvents: newHCEvents(ctx, api, tsc, uint64(gcConfidence)),
|
||||||
cs: api,
|
|
||||||
tsc: tsc,
|
|
||||||
ctx: ctx,
|
|
||||||
gcConfidence: uint64(gcConfidence),
|
|
||||||
|
|
||||||
confQueue: map[triggerH]map[msgH][]*queuedEvent{},
|
|
||||||
revertQueue: map[msgH][]triggerH{},
|
|
||||||
triggers: map[triggerId]*callHandler{},
|
|
||||||
matchers: map[triggerId][]MatchFunc{},
|
|
||||||
timeouts: map[abi.ChainEpoch]map[triggerId]int{},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
e.ready.Add(1)
|
e.ready.Add(1)
|
||||||
@@ -143,7 +132,7 @@ func (e *Events) listenHeadChangesOnce(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
e.readyOnce.Do(func() {
|
e.readyOnce.Do(func() {
|
||||||
e.at = cur[0].Val.Height()
|
e.lastTs = cur[0].Val
|
||||||
|
|
||||||
e.ready.Done()
|
e.ready.Done()
|
||||||
})
|
})
|
||||||
@@ -186,5 +175,5 @@ func (e *Events) headChange(rev, app []*types.TipSet) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return e.headChangeCalled(rev, app)
|
return e.processHeadChangeEvent(rev, app)
|
||||||
}
|
}
|
||||||
|
|||||||
+373
-118
@@ -13,8 +13,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const NoTimeout = math.MaxInt64
|
const NoTimeout = math.MaxInt64
|
||||||
|
const NoHeight = abi.ChainEpoch(-1)
|
||||||
|
|
||||||
type triggerId = uint64
|
type triggerID = uint64
|
||||||
|
|
||||||
// msgH is the block height at which a message was present / event has happened
|
// msgH is the block height at which a message was present / event has happened
|
||||||
type msgH = abi.ChainEpoch
|
type msgH = abi.ChainEpoch
|
||||||
@@ -23,53 +24,60 @@ type msgH = abi.ChainEpoch
|
|||||||
// message (msgH+confidence)
|
// message (msgH+confidence)
|
||||||
type triggerH = abi.ChainEpoch
|
type triggerH = abi.ChainEpoch
|
||||||
|
|
||||||
// `ts` is the tipset, in which the `msg` is included.
|
type eventData interface{}
|
||||||
|
|
||||||
|
// EventHandler arguments:
|
||||||
|
// `prevTs` is the previous tipset, eg the "from" tipset for a state change.
|
||||||
|
// `ts` is the event tipset, eg the tipset in which the `msg` is included.
|
||||||
// `curH`-`ts.Height` = `confidence`
|
// `curH`-`ts.Height` = `confidence`
|
||||||
type CalledHandler func(msg *types.Message, rec *types.MessageReceipt, ts *types.TipSet, curH abi.ChainEpoch) (more bool, err error)
|
type EventHandler func(data eventData, prevTs, ts *types.TipSet, curH abi.ChainEpoch) (more bool, err error)
|
||||||
|
|
||||||
// CheckFunc is used for atomicity guarantees. If the condition the callbacks
|
// CheckFunc is used for atomicity guarantees. If the condition the callbacks
|
||||||
// wait for has already happened in tipset `ts`
|
// wait for has already happened in tipset `ts`
|
||||||
//
|
//
|
||||||
// If `done` is true, timeout won't be triggered
|
// If `done` is true, timeout won't be triggered
|
||||||
// If `more` is false, no messages will be sent to CalledHandler (RevertHandler
|
// If `more` is false, no messages will be sent to EventHandler (RevertHandler
|
||||||
// may still be called)
|
// may still be called)
|
||||||
type CheckFunc func(ts *types.TipSet) (done bool, more bool, err error)
|
type CheckFunc func(ts *types.TipSet) (done bool, more bool, err error)
|
||||||
|
|
||||||
type MatchFunc func(msg *types.Message) (bool, error)
|
// Keep track of information for an event handler
|
||||||
|
type handlerInfo struct {
|
||||||
type callHandler struct {
|
|
||||||
confidence int
|
confidence int
|
||||||
timeout abi.ChainEpoch
|
timeout abi.ChainEpoch
|
||||||
|
|
||||||
disabled bool // TODO: GC after gcConfidence reached
|
disabled bool // TODO: GC after gcConfidence reached
|
||||||
|
|
||||||
handle CalledHandler
|
handle EventHandler
|
||||||
revert RevertHandler
|
revert RevertHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When a change occurs, a queuedEvent is created and put into a queue
|
||||||
|
// until the required confidence is reached
|
||||||
type queuedEvent struct {
|
type queuedEvent struct {
|
||||||
trigger triggerId
|
trigger triggerID
|
||||||
|
|
||||||
h abi.ChainEpoch
|
prevH abi.ChainEpoch
|
||||||
msg *types.Message
|
h abi.ChainEpoch
|
||||||
|
data eventData
|
||||||
|
|
||||||
called bool
|
called bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type calledEvents struct {
|
// Manages chain head change events, which may be forward (new tipset added to
|
||||||
cs eventApi
|
// chain) or backward (chain branch discarded in favour of heavier branch)
|
||||||
|
type hcEvents struct {
|
||||||
|
cs eventAPI
|
||||||
tsc *tipSetCache
|
tsc *tipSetCache
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
gcConfidence uint64
|
gcConfidence uint64
|
||||||
|
|
||||||
at abi.ChainEpoch
|
lastTs *types.TipSet
|
||||||
|
|
||||||
lk sync.Mutex
|
lk sync.Mutex
|
||||||
|
|
||||||
ctr triggerId
|
ctr triggerID
|
||||||
|
|
||||||
triggers map[triggerId]*callHandler
|
triggers map[triggerID]*handlerInfo
|
||||||
matchers map[triggerId][]MatchFunc
|
|
||||||
|
|
||||||
// maps block heights to events
|
// maps block heights to events
|
||||||
// [triggerH][msgH][event]
|
// [triggerH][msgH][event]
|
||||||
@@ -78,29 +86,81 @@ type calledEvents struct {
|
|||||||
// [msgH][triggerH]
|
// [msgH][triggerH]
|
||||||
revertQueue map[msgH][]triggerH
|
revertQueue map[msgH][]triggerH
|
||||||
|
|
||||||
// [timeoutH+confidence][triggerId]{calls}
|
// [timeoutH+confidence][triggerID]{calls}
|
||||||
timeouts map[abi.ChainEpoch]map[triggerId]int
|
timeouts map[abi.ChainEpoch]map[triggerID]int
|
||||||
|
|
||||||
|
messageEvents
|
||||||
|
watcherEvents
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *calledEvents) headChangeCalled(rev, app []*types.TipSet) error {
|
func newHCEvents(ctx context.Context, cs eventAPI, tsc *tipSetCache, gcConfidence uint64) *hcEvents {
|
||||||
|
e := hcEvents{
|
||||||
|
ctx: ctx,
|
||||||
|
cs: cs,
|
||||||
|
tsc: tsc,
|
||||||
|
gcConfidence: gcConfidence,
|
||||||
|
|
||||||
|
confQueue: map[triggerH]map[msgH][]*queuedEvent{},
|
||||||
|
revertQueue: map[msgH][]triggerH{},
|
||||||
|
triggers: map[triggerID]*handlerInfo{},
|
||||||
|
timeouts: map[abi.ChainEpoch]map[triggerID]int{},
|
||||||
|
}
|
||||||
|
|
||||||
|
e.messageEvents = newMessageEvents(ctx, &e, cs)
|
||||||
|
e.watcherEvents = newWatcherEvents(ctx, &e, cs)
|
||||||
|
|
||||||
|
return &e
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when there is a change to the head with tipsets to be
|
||||||
|
// reverted / applied
|
||||||
|
func (e *hcEvents) processHeadChangeEvent(rev, app []*types.TipSet) error {
|
||||||
|
e.lk.Lock()
|
||||||
|
defer e.lk.Unlock()
|
||||||
|
|
||||||
for _, ts := range rev {
|
for _, ts := range rev {
|
||||||
e.handleReverts(ts)
|
e.handleReverts(ts)
|
||||||
e.at = ts.Height()
|
e.lastTs = ts
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, ts := range app {
|
for _, ts := range app {
|
||||||
// called triggers
|
// Check if the head change caused any state changes that we were
|
||||||
e.checkNewCalls(ts)
|
// waiting for
|
||||||
for ; e.at <= ts.Height(); e.at++ {
|
stateChanges := e.watcherEvents.checkStateChanges(e.lastTs, ts)
|
||||||
e.applyWithConfidence(ts, e.at)
|
|
||||||
|
// Queue up calls until there have been enough blocks to reach
|
||||||
|
// confidence on the state changes
|
||||||
|
for tid, data := range stateChanges {
|
||||||
|
e.queueForConfidence(tid, data, e.lastTs, ts)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the head change included any new message calls
|
||||||
|
newCalls, err := e.messageEvents.checkNewCalls(ts)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Queue up calls until there have been enough blocks to reach
|
||||||
|
// confidence on the message calls
|
||||||
|
for tid, data := range newCalls {
|
||||||
|
e.queueForConfidence(tid, data, nil, ts)
|
||||||
|
}
|
||||||
|
|
||||||
|
for at := e.lastTs.Height(); at <= ts.Height(); at++ {
|
||||||
|
// Apply any queued events and timeouts that were targeted at the
|
||||||
|
// current chain height
|
||||||
|
e.applyWithConfidence(ts, at)
|
||||||
e.applyTimeouts(ts)
|
e.applyTimeouts(ts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update the latest known tipset
|
||||||
|
e.lastTs = ts
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *calledEvents) handleReverts(ts *types.TipSet) {
|
func (e *hcEvents) handleReverts(ts *types.TipSet) {
|
||||||
reverts, ok := e.revertQueue[ts.Height()]
|
reverts, ok := e.revertQueue[ts.Height()]
|
||||||
if !ok {
|
if !ok {
|
||||||
return // nothing to do
|
return // nothing to do
|
||||||
@@ -116,7 +176,7 @@ func (e *calledEvents) handleReverts(ts *types.TipSet) {
|
|||||||
trigger := e.triggers[event.trigger]
|
trigger := e.triggers[event.trigger]
|
||||||
|
|
||||||
if err := trigger.revert(e.ctx, ts); err != nil {
|
if err := trigger.revert(e.ctx, ts); err != nil {
|
||||||
log.Errorf("reverting chain trigger (call %s.%d() @H %d, called @ %d) failed: %s", event.msg.To, event.msg.Method, ts.Height(), triggerH, err)
|
log.Errorf("reverting chain trigger (@H %d, triggered @ %d) failed: %s", ts.Height(), triggerH, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete(e.confQueue[triggerH], ts.Height())
|
delete(e.confQueue[triggerH], ts.Height())
|
||||||
@@ -124,42 +184,15 @@ func (e *calledEvents) handleReverts(ts *types.TipSet) {
|
|||||||
delete(e.revertQueue, ts.Height())
|
delete(e.revertQueue, ts.Height())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *calledEvents) checkNewCalls(ts *types.TipSet) {
|
// Queue up events until the chain has reached a height that reflects the
|
||||||
pts, err := e.cs.ChainGetTipSet(e.ctx, ts.Parents()) // we actually care about messages in the parent tipset here
|
// desired confidence
|
||||||
if err != nil {
|
func (e *hcEvents) queueForConfidence(trigID uint64, data eventData, prevTs, ts *types.TipSet) {
|
||||||
log.Errorf("getting parent tipset in checkNewCalls: %s", err)
|
trigger := e.triggers[trigID]
|
||||||
return
|
|
||||||
|
prevH := NoHeight
|
||||||
|
if prevTs != nil {
|
||||||
|
prevH = prevTs.Height()
|
||||||
}
|
}
|
||||||
|
|
||||||
e.messagesForTs(pts, func(msg *types.Message) {
|
|
||||||
// TODO: provide receipts
|
|
||||||
|
|
||||||
for tid, matchFns := range e.matchers {
|
|
||||||
var matched bool
|
|
||||||
for _, matchFn := range matchFns {
|
|
||||||
ok, err := matchFn(msg)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("event matcher failed: %s", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
matched = ok
|
|
||||||
|
|
||||||
if matched {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if matched {
|
|
||||||
e.queueForConfidence(tid, msg, ts)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *calledEvents) queueForConfidence(triggerId uint64, msg *types.Message, ts *types.TipSet) {
|
|
||||||
trigger := e.triggers[triggerId]
|
|
||||||
|
|
||||||
appliedH := ts.Height()
|
appliedH := ts.Height()
|
||||||
|
|
||||||
triggerH := appliedH + abi.ChainEpoch(trigger.confidence)
|
triggerH := appliedH + abi.ChainEpoch(trigger.confidence)
|
||||||
@@ -171,18 +204,20 @@ func (e *calledEvents) queueForConfidence(triggerId uint64, msg *types.Message,
|
|||||||
}
|
}
|
||||||
|
|
||||||
byOrigH[appliedH] = append(byOrigH[appliedH], &queuedEvent{
|
byOrigH[appliedH] = append(byOrigH[appliedH], &queuedEvent{
|
||||||
trigger: triggerId,
|
trigger: trigID,
|
||||||
|
prevH: prevH,
|
||||||
h: appliedH,
|
h: appliedH,
|
||||||
msg: msg,
|
data: data,
|
||||||
})
|
})
|
||||||
|
|
||||||
e.revertQueue[appliedH] = append(e.revertQueue[appliedH], triggerH)
|
e.revertQueue[appliedH] = append(e.revertQueue[appliedH], triggerH)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *calledEvents) applyWithConfidence(ts *types.TipSet, height abi.ChainEpoch) {
|
// Apply any events that were waiting for this chain height for confidence
|
||||||
|
func (e *hcEvents) applyWithConfidence(ts *types.TipSet, height abi.ChainEpoch) {
|
||||||
byOrigH, ok := e.confQueue[height]
|
byOrigH, ok := e.confQueue[height]
|
||||||
if !ok {
|
if !ok {
|
||||||
return // no triggers at thin height
|
return // no triggers at this height
|
||||||
}
|
}
|
||||||
|
|
||||||
for origH, events := range byOrigH {
|
for origH, events := range byOrigH {
|
||||||
@@ -201,15 +236,20 @@ func (e *calledEvents) applyWithConfidence(ts *types.TipSet, height abi.ChainEpo
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
rec, err := e.cs.StateGetReceipt(e.ctx, event.msg.Cid(), ts.Key())
|
// Previous tipset - this is relevant for example in a state change
|
||||||
if err != nil {
|
// from one tipset to another
|
||||||
log.Error(err)
|
var prevTs *types.TipSet
|
||||||
return
|
if event.prevH != NoHeight {
|
||||||
|
prevTs, err = e.tsc.get(event.prevH)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("events: applyWithConfidence didn't find tipset for previous event; wanted %d; current %d", event.prevH, height)
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
more, err := trigger.handle(event.msg, rec, triggerTs, height)
|
more, err := trigger.handle(event.data, prevTs, triggerTs, height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("chain trigger (call %s.%d() @H %d, called @ %d) failed: %s", event.msg.To, event.msg.Method, origH, height, err)
|
log.Errorf("chain trigger (@H %d, triggered @ %d) failed: %s", origH, height, err)
|
||||||
continue // don't revert failed calls
|
continue // don't revert failed calls
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,17 +265,18 @@ func (e *calledEvents) applyWithConfidence(ts *types.TipSet, height abi.ChainEpo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *calledEvents) applyTimeouts(ts *types.TipSet) {
|
// Apply any timeouts that expire at this height
|
||||||
|
func (e *hcEvents) applyTimeouts(ts *types.TipSet) {
|
||||||
triggers, ok := e.timeouts[ts.Height()]
|
triggers, ok := e.timeouts[ts.Height()]
|
||||||
if !ok {
|
if !ok {
|
||||||
return // nothing to do
|
return // nothing to do
|
||||||
}
|
}
|
||||||
|
|
||||||
for triggerId, calls := range triggers {
|
for triggerID, calls := range triggers {
|
||||||
if calls > 0 {
|
if calls > 0 {
|
||||||
continue // don't timeout if the method was called
|
continue // don't timeout if the method was called
|
||||||
}
|
}
|
||||||
trigger := e.triggers[triggerId]
|
trigger := e.triggers[triggerID]
|
||||||
if trigger.disabled {
|
if trigger.disabled {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -255,12 +296,225 @@ func (e *calledEvents) applyTimeouts(ts *types.TipSet) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *calledEvents) messagesForTs(ts *types.TipSet, consume func(*types.Message)) {
|
// Listen for an event
|
||||||
|
// - CheckFunc: immediately checks if the event already occurred
|
||||||
|
// - EventHandler: called when the event has occurred, after confidence tipsets
|
||||||
|
// - RevertHandler: called if the chain head changes causing the event to revert
|
||||||
|
// - confidence: wait this many tipsets before calling EventHandler
|
||||||
|
// - timeout: at this chain height, timeout on waiting for this event
|
||||||
|
func (e *hcEvents) onHeadChanged(check CheckFunc, hnd EventHandler, rev RevertHandler, confidence int, timeout abi.ChainEpoch) (triggerID, error) {
|
||||||
|
e.lk.Lock()
|
||||||
|
defer e.lk.Unlock()
|
||||||
|
|
||||||
|
// Check if the event has already occurred
|
||||||
|
ts := e.tsc.best()
|
||||||
|
done, more, err := check(ts)
|
||||||
|
if err != nil {
|
||||||
|
return 0, xerrors.Errorf("called check error (h: %d): %w", ts.Height(), err)
|
||||||
|
}
|
||||||
|
if done {
|
||||||
|
timeout = NoTimeout
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a trigger for the event
|
||||||
|
id := e.ctr
|
||||||
|
e.ctr++
|
||||||
|
|
||||||
|
e.triggers[id] = &handlerInfo{
|
||||||
|
confidence: confidence,
|
||||||
|
timeout: timeout + abi.ChainEpoch(confidence),
|
||||||
|
|
||||||
|
disabled: !more,
|
||||||
|
|
||||||
|
handle: hnd,
|
||||||
|
revert: rev,
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there's a timeout, set up a timeout check at that height
|
||||||
|
if timeout != NoTimeout {
|
||||||
|
if e.timeouts[timeout+abi.ChainEpoch(confidence)] == nil {
|
||||||
|
e.timeouts[timeout+abi.ChainEpoch(confidence)] = map[uint64]int{}
|
||||||
|
}
|
||||||
|
e.timeouts[timeout+abi.ChainEpoch(confidence)][id] = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return id, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// headChangeAPI is used to allow the composed event APIs to call back to hcEvents
|
||||||
|
// to listen for changes
|
||||||
|
type headChangeAPI interface {
|
||||||
|
onHeadChanged(check CheckFunc, hnd EventHandler, rev RevertHandler, confidence int, timeout abi.ChainEpoch) (triggerID, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// watcherEvents watches for a state change
|
||||||
|
type watcherEvents struct {
|
||||||
|
ctx context.Context
|
||||||
|
cs eventAPI
|
||||||
|
hcAPI headChangeAPI
|
||||||
|
|
||||||
|
lk sync.RWMutex
|
||||||
|
matchers map[triggerID]StateMatchFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
func newWatcherEvents(ctx context.Context, hcAPI headChangeAPI, cs eventAPI) watcherEvents {
|
||||||
|
return watcherEvents{
|
||||||
|
ctx: ctx,
|
||||||
|
cs: cs,
|
||||||
|
hcAPI: hcAPI,
|
||||||
|
matchers: make(map[triggerID]StateMatchFunc),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run each of the matchers against the previous and current state to see if
|
||||||
|
// there's a change
|
||||||
|
func (we *watcherEvents) checkStateChanges(oldState, newState *types.TipSet) map[triggerID]eventData {
|
||||||
|
we.lk.RLock()
|
||||||
|
defer we.lk.RUnlock()
|
||||||
|
|
||||||
|
res := make(map[triggerID]eventData)
|
||||||
|
for tid, matchFn := range we.matchers {
|
||||||
|
ok, data, err := matchFn(oldState, newState)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("event diff fn failed: %s", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if ok {
|
||||||
|
res[tid] = data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// StateChange represents a change in state
|
||||||
|
type StateChange interface{}
|
||||||
|
|
||||||
|
// StateChangeHandler arguments:
|
||||||
|
// `oldTs` is the state "from" tipset
|
||||||
|
// `newTs` is the state "to" tipset
|
||||||
|
// `states` is the change in state
|
||||||
|
// `curH`-`ts.Height` = `confidence`
|
||||||
|
type StateChangeHandler func(oldTs, newTs *types.TipSet, states StateChange, curH abi.ChainEpoch) (more bool, err error)
|
||||||
|
|
||||||
|
type StateMatchFunc func(oldTs, newTs *types.TipSet) (bool, StateChange, error)
|
||||||
|
|
||||||
|
// StateChanged registers a callback which is triggered when a specified state
|
||||||
|
// change occurs or a timeout is reached.
|
||||||
|
//
|
||||||
|
// * `CheckFunc` callback is invoked immediately with a recent tipset, it
|
||||||
|
// returns two booleans - `done`, and `more`.
|
||||||
|
//
|
||||||
|
// * `done` should be true when some on-chain state change we are waiting
|
||||||
|
// for has happened. When `done` is set to true, timeout trigger is disabled.
|
||||||
|
//
|
||||||
|
// * `more` should be false when we don't want to receive new notifications
|
||||||
|
// through StateChangeHandler. Note that notifications may still be delivered to
|
||||||
|
// RevertHandler
|
||||||
|
//
|
||||||
|
// * `StateChangeHandler` is called when the specified state change was observed
|
||||||
|
// on-chain, and a confidence threshold was reached, or the specified `timeout`
|
||||||
|
// height was reached with no state change observed. When this callback is
|
||||||
|
// invoked on a timeout, `oldState` and `newState` are set to nil.
|
||||||
|
// This callback returns a boolean specifying whether further notifications
|
||||||
|
// should be sent, like `more` return param from `CheckFunc` above.
|
||||||
|
//
|
||||||
|
// * `RevertHandler` is called after apply handler, when we drop the tipset
|
||||||
|
// containing the message. The tipset passed as the argument is the tipset
|
||||||
|
// that is being dropped. Note that the event dropped may be re-applied
|
||||||
|
// in a different tipset in small amount of time.
|
||||||
|
//
|
||||||
|
// * `StateMatchFunc` is called against each tipset state. If there is a match,
|
||||||
|
// the state change is queued up until the confidence interval has elapsed (and
|
||||||
|
// `StateChangeHandler` is called)
|
||||||
|
func (we *watcherEvents) StateChanged(check CheckFunc, scHnd StateChangeHandler, rev RevertHandler, confidence int, timeout abi.ChainEpoch, mf StateMatchFunc) error {
|
||||||
|
hnd := func(data eventData, prevTs, ts *types.TipSet, height abi.ChainEpoch) (bool, error) {
|
||||||
|
states, ok := data.(StateChange)
|
||||||
|
if data != nil && !ok {
|
||||||
|
panic("expected StateChange")
|
||||||
|
}
|
||||||
|
|
||||||
|
return scHnd(prevTs, ts, states, height)
|
||||||
|
}
|
||||||
|
|
||||||
|
id, err := we.hcAPI.onHeadChanged(check, hnd, rev, confidence, timeout)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
we.lk.Lock()
|
||||||
|
defer we.lk.Unlock()
|
||||||
|
we.matchers[id] = mf
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// messageEvents watches for message calls to actors
|
||||||
|
type messageEvents struct {
|
||||||
|
ctx context.Context
|
||||||
|
cs eventAPI
|
||||||
|
hcAPI headChangeAPI
|
||||||
|
|
||||||
|
lk sync.RWMutex
|
||||||
|
matchers map[triggerID][]MsgMatchFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMessageEvents(ctx context.Context, hcAPI headChangeAPI, cs eventAPI) messageEvents {
|
||||||
|
return messageEvents{
|
||||||
|
ctx: ctx,
|
||||||
|
cs: cs,
|
||||||
|
hcAPI: hcAPI,
|
||||||
|
matchers: map[triggerID][]MsgMatchFunc{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if there are any new actor calls
|
||||||
|
func (me *messageEvents) checkNewCalls(ts *types.TipSet) (map[triggerID]eventData, error) {
|
||||||
|
pts, err := me.cs.ChainGetTipSet(me.ctx, ts.Parents()) // we actually care about messages in the parent tipset here
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("getting parent tipset in checkNewCalls: %s", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
me.lk.RLock()
|
||||||
|
defer me.lk.RUnlock()
|
||||||
|
|
||||||
|
res := make(map[triggerID]eventData)
|
||||||
|
me.messagesForTs(pts, func(msg *types.Message) {
|
||||||
|
// TODO: provide receipts
|
||||||
|
|
||||||
|
for tid, matchFns := range me.matchers {
|
||||||
|
var matched bool
|
||||||
|
for _, matchFn := range matchFns {
|
||||||
|
ok, err := matchFn(msg)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("event matcher failed: %s", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
matched = ok
|
||||||
|
|
||||||
|
if matched {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if matched {
|
||||||
|
res[tid] = msg
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the messages in a tipset
|
||||||
|
func (me *messageEvents) messagesForTs(ts *types.TipSet, consume func(*types.Message)) {
|
||||||
seen := map[cid.Cid]struct{}{}
|
seen := map[cid.Cid]struct{}{}
|
||||||
|
|
||||||
for _, tsb := range ts.Blocks() {
|
for _, tsb := range ts.Blocks() {
|
||||||
|
|
||||||
msgs, err := e.cs.ChainGetBlockMessages(context.TODO(), tsb.Cid())
|
msgs, err := me.cs.ChainGetBlockMessages(context.TODO(), tsb.Cid())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("messagesForTs MessagesForBlock failed (ts.H=%d, Bcid:%s, B.Mcid:%s): %s", ts.Height(), tsb.Cid(), tsb.Messages, err)
|
log.Errorf("messagesForTs MessagesForBlock failed (ts.H=%d, Bcid:%s, B.Mcid:%s): %s", ts.Height(), tsb.Cid(), tsb.Messages, err)
|
||||||
// this is quite bad, but probably better than missing all the other updates
|
// this is quite bad, but probably better than missing all the other updates
|
||||||
@@ -289,20 +543,27 @@ func (e *calledEvents) messagesForTs(ts *types.TipSet, consume func(*types.Messa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called registers a callbacks which are triggered when a specified method is
|
// MsgHandler arguments:
|
||||||
|
// `ts` is the tipset, in which the `msg` is included.
|
||||||
|
// `curH`-`ts.Height` = `confidence`
|
||||||
|
type MsgHandler func(msg *types.Message, rec *types.MessageReceipt, ts *types.TipSet, curH abi.ChainEpoch) (more bool, err error)
|
||||||
|
|
||||||
|
type MsgMatchFunc func(msg *types.Message) (bool, error)
|
||||||
|
|
||||||
|
// Called registers a callback which is triggered when a specified method is
|
||||||
// called on an actor, or a timeout is reached.
|
// called on an actor, or a timeout is reached.
|
||||||
//
|
//
|
||||||
// * `CheckFunc` callback is invoked immediately with a recent tipset, it
|
// * `CheckFunc` callback is invoked immediately with a recent tipset, it
|
||||||
// returns two booleans - `done`, and `more`.
|
// returns two booleans - `done`, and `more`.
|
||||||
//
|
//
|
||||||
// * `done` should be true when some on-chain action we are waiting for has
|
// * `done` should be true when some on-chain action we are waiting for has
|
||||||
// happened. When `done` is set to true, timeout trigger is disabled.
|
// happened. When `done` is set to true, timeout trigger is disabled.
|
||||||
//
|
//
|
||||||
// * `more` should be false when we don't want to receive new notifications
|
// * `more` should be false when we don't want to receive new notifications
|
||||||
// through CalledHandler. Note that notifications may still be delivered to
|
// through MsgHandler. Note that notifications may still be delivered to
|
||||||
// RevertHandler
|
// RevertHandler
|
||||||
//
|
//
|
||||||
// * `CalledHandler` is called when the specified event was observed on-chain,
|
// * `MsgHandler` is called when the specified event was observed on-chain,
|
||||||
// and a confidence threshold was reached, or the specified `timeout` height
|
// and a confidence threshold was reached, or the specified `timeout` height
|
||||||
// was reached with no events observed. When this callback is invoked on a
|
// was reached with no events observed. When this callback is invoked on a
|
||||||
// timeout, `msg` is set to nil. This callback returns a boolean specifying
|
// timeout, `msg` is set to nil. This callback returns a boolean specifying
|
||||||
@@ -313,44 +574,38 @@ func (e *calledEvents) messagesForTs(ts *types.TipSet, consume func(*types.Messa
|
|||||||
// containing the message. The tipset passed as the argument is the tipset
|
// containing the message. The tipset passed as the argument is the tipset
|
||||||
// that is being dropped. Note that the message dropped may be re-applied
|
// that is being dropped. Note that the message dropped may be re-applied
|
||||||
// in a different tipset in small amount of time.
|
// in a different tipset in small amount of time.
|
||||||
func (e *calledEvents) Called(check CheckFunc, hnd CalledHandler, rev RevertHandler, confidence int, timeout abi.ChainEpoch, mf MatchFunc) error {
|
//
|
||||||
e.lk.Lock()
|
// * `MsgMatchFunc` is called against each message. If there is a match, the
|
||||||
defer e.lk.Unlock()
|
// message is queued up until the confidence interval has elapsed (and
|
||||||
|
// `MsgHandler` is called)
|
||||||
ts := e.tsc.best()
|
func (me *messageEvents) Called(check CheckFunc, msgHnd MsgHandler, rev RevertHandler, confidence int, timeout abi.ChainEpoch, mf MsgMatchFunc) error {
|
||||||
done, more, err := check(ts)
|
hnd := func(data eventData, prevTs, ts *types.TipSet, height abi.ChainEpoch) (bool, error) {
|
||||||
if err != nil {
|
msg, ok := data.(*types.Message)
|
||||||
return xerrors.Errorf("called check error (h: %d): %w", ts.Height(), err)
|
if data != nil && !ok {
|
||||||
}
|
panic("expected msg")
|
||||||
if done {
|
|
||||||
timeout = NoTimeout
|
|
||||||
}
|
|
||||||
|
|
||||||
id := e.ctr
|
|
||||||
e.ctr++
|
|
||||||
|
|
||||||
e.triggers[id] = &callHandler{
|
|
||||||
confidence: confidence,
|
|
||||||
timeout: timeout + abi.ChainEpoch(confidence),
|
|
||||||
|
|
||||||
disabled: !more,
|
|
||||||
|
|
||||||
handle: hnd,
|
|
||||||
revert: rev,
|
|
||||||
}
|
|
||||||
|
|
||||||
e.matchers[id] = append(e.matchers[id], mf)
|
|
||||||
|
|
||||||
if timeout != NoTimeout {
|
|
||||||
if e.timeouts[timeout+abi.ChainEpoch(confidence)] == nil {
|
|
||||||
e.timeouts[timeout+abi.ChainEpoch(confidence)] = map[uint64]int{}
|
|
||||||
}
|
}
|
||||||
e.timeouts[timeout+abi.ChainEpoch(confidence)][id] = 0
|
|
||||||
|
rec, err := me.cs.StateGetReceipt(me.ctx, msg.Cid(), ts.Key())
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return msgHnd(msg, rec, ts, height)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
id, err := me.hcAPI.onHeadChanged(check, hnd, rev, confidence, timeout)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
me.lk.Lock()
|
||||||
|
defer me.lk.Unlock()
|
||||||
|
me.matchers[id] = append(me.matchers[id], mf)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *calledEvents) CalledMsg(ctx context.Context, hnd CalledHandler, rev RevertHandler, confidence int, timeout abi.ChainEpoch, msg types.ChainMsg) error {
|
// Convenience function for checking and matching messages
|
||||||
return e.Called(e.CheckMsg(ctx, msg, hnd), hnd, rev, confidence, timeout, e.MatchMsg(msg.VMMessage()))
|
func (me *messageEvents) CalledMsg(ctx context.Context, hnd MsgHandler, rev RevertHandler, confidence int, timeout abi.ChainEpoch, msg types.ChainMsg) error {
|
||||||
|
return me.Called(me.CheckMsg(ctx, msg, hnd), hnd, rev, confidence, timeout, me.MatchMsg(msg.VMMessage()))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,23 +15,26 @@ type heightEvents struct {
|
|||||||
tsc *tipSetCache
|
tsc *tipSetCache
|
||||||
gcConfidence abi.ChainEpoch
|
gcConfidence abi.ChainEpoch
|
||||||
|
|
||||||
ctr triggerId
|
ctr triggerID
|
||||||
|
|
||||||
heightTriggers map[triggerId]*heightHandler
|
heightTriggers map[triggerID]*heightHandler
|
||||||
|
|
||||||
htTriggerHeights map[triggerH][]triggerId
|
htTriggerHeights map[triggerH][]triggerID
|
||||||
htHeights map[msgH][]triggerId
|
htHeights map[msgH][]triggerID
|
||||||
|
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *heightEvents) headChangeAt(rev, app []*types.TipSet) error {
|
func (e *heightEvents) headChangeAt(rev, app []*types.TipSet) error {
|
||||||
|
|
||||||
ctx, span := trace.StartSpan(e.ctx, "events.HeightHeadChange")
|
ctx, span := trace.StartSpan(e.ctx, "events.HeightHeadChange")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
span.AddAttributes(trace.Int64Attribute("endHeight", int64(app[0].Height())))
|
span.AddAttributes(trace.Int64Attribute("endHeight", int64(app[0].Height())))
|
||||||
span.AddAttributes(trace.Int64Attribute("reverts", int64(len(rev))))
|
span.AddAttributes(trace.Int64Attribute("reverts", int64(len(rev))))
|
||||||
span.AddAttributes(trace.Int64Attribute("applies", int64(len(app))))
|
span.AddAttributes(trace.Int64Attribute("applies", int64(len(app))))
|
||||||
|
|
||||||
|
e.lk.Lock()
|
||||||
|
defer e.lk.Unlock()
|
||||||
for _, ts := range rev {
|
for _, ts := range rev {
|
||||||
// TODO: log error if h below gcconfidence
|
// TODO: log error if h below gcconfidence
|
||||||
// revert height-based triggers
|
// revert height-based triggers
|
||||||
@@ -40,7 +43,10 @@ func (e *heightEvents) headChangeAt(rev, app []*types.TipSet) error {
|
|||||||
for _, tid := range e.htHeights[h] {
|
for _, tid := range e.htHeights[h] {
|
||||||
ctx, span := trace.StartSpan(ctx, "events.HeightRevert")
|
ctx, span := trace.StartSpan(ctx, "events.HeightRevert")
|
||||||
|
|
||||||
err := e.heightTriggers[tid].revert(ctx, ts)
|
rev := e.heightTriggers[tid].revert
|
||||||
|
e.lk.Unlock()
|
||||||
|
err := rev(ctx, ts)
|
||||||
|
e.lk.Lock()
|
||||||
e.heightTriggers[tid].called = false
|
e.heightTriggers[tid].called = false
|
||||||
|
|
||||||
span.End()
|
span.End()
|
||||||
@@ -98,8 +104,10 @@ func (e *heightEvents) headChangeAt(rev, app []*types.TipSet) error {
|
|||||||
|
|
||||||
ctx, span := trace.StartSpan(ctx, "events.HeightApply")
|
ctx, span := trace.StartSpan(ctx, "events.HeightApply")
|
||||||
span.AddAttributes(trace.BoolAttribute("immediate", false))
|
span.AddAttributes(trace.BoolAttribute("immediate", false))
|
||||||
|
handle := hnd.handle
|
||||||
err = hnd.handle(ctx, incTs, h)
|
e.lk.Unlock()
|
||||||
|
err = handle(ctx, incTs, h)
|
||||||
|
e.lk.Lock()
|
||||||
span.End()
|
span.End()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+249
-5
@@ -211,15 +211,14 @@ func (fcs *fakeCS) advance(rev, app int, msgs map[int]cid.Cid, nulls ...int) { /
|
|||||||
fcs.sub(revs, apps)
|
fcs.sub(revs, apps)
|
||||||
|
|
||||||
fcs.sync.Lock()
|
fcs.sync.Lock()
|
||||||
fcs.sync.Unlock()
|
fcs.sync.Unlock() //nolint:staticcheck
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fcs *fakeCS) notifDone() {
|
func (fcs *fakeCS) notifDone() {
|
||||||
fcs.sync.Unlock()
|
fcs.sync.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ eventApi = &fakeCS{}
|
var _ eventAPI = &fakeCS{}
|
||||||
|
|
||||||
func TestAt(t *testing.T) {
|
func TestAt(t *testing.T) {
|
||||||
fcs := &fakeCS{
|
fcs := &fakeCS{
|
||||||
@@ -1005,8 +1004,6 @@ func TestRemoveTriggersOnMessage(t *testing.T) {
|
|||||||
return false, true, nil
|
return false, true, nil
|
||||||
}, func(msg *types.Message, rec *types.MessageReceipt, ts *types.TipSet, curH abi.ChainEpoch) (bool, error) {
|
}, func(msg *types.Message, rec *types.MessageReceipt, ts *types.TipSet, curH abi.ChainEpoch) (bool, error) {
|
||||||
require.Equal(t, false, applied)
|
require.Equal(t, false, applied)
|
||||||
fmt.Println(msg == nil)
|
|
||||||
fmt.Println(curH)
|
|
||||||
applied = true
|
applied = true
|
||||||
return more, nil
|
return more, nil
|
||||||
}, func(_ context.Context, ts *types.TipSet) error {
|
}, func(_ context.Context, ts *types.TipSet) error {
|
||||||
@@ -1068,3 +1065,250 @@ func TestRemoveTriggersOnMessage(t *testing.T) {
|
|||||||
require.Equal(t, true, applied)
|
require.Equal(t, true, applied)
|
||||||
require.Equal(t, false, reverted)
|
require.Equal(t, false, reverted)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type testStateChange struct {
|
||||||
|
from string
|
||||||
|
to string
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStateChanged(t *testing.T) {
|
||||||
|
fcs := &fakeCS{
|
||||||
|
t: t,
|
||||||
|
h: 1,
|
||||||
|
|
||||||
|
msgs: map[cid.Cid]fakeMsg{},
|
||||||
|
blkMsgs: map[cid.Cid]cid.Cid{},
|
||||||
|
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
|
||||||
|
}
|
||||||
|
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
|
||||||
|
|
||||||
|
events := NewEvents(context.Background(), fcs)
|
||||||
|
|
||||||
|
more := true
|
||||||
|
var applied, reverted bool
|
||||||
|
var appliedData StateChange
|
||||||
|
var appliedOldTs *types.TipSet
|
||||||
|
var appliedNewTs *types.TipSet
|
||||||
|
var appliedH abi.ChainEpoch
|
||||||
|
var matchData StateChange
|
||||||
|
|
||||||
|
confidence := 3
|
||||||
|
timeout := abi.ChainEpoch(20)
|
||||||
|
|
||||||
|
err := events.StateChanged(func(ts *types.TipSet) (d bool, m bool, e error) {
|
||||||
|
return false, true, nil
|
||||||
|
}, func(oldTs, newTs *types.TipSet, data StateChange, curH abi.ChainEpoch) (bool, error) {
|
||||||
|
require.Equal(t, false, applied)
|
||||||
|
applied = true
|
||||||
|
appliedData = data
|
||||||
|
appliedOldTs = oldTs
|
||||||
|
appliedNewTs = newTs
|
||||||
|
appliedH = curH
|
||||||
|
return more, nil
|
||||||
|
}, func(_ context.Context, ts *types.TipSet) error {
|
||||||
|
reverted = true
|
||||||
|
return nil
|
||||||
|
}, confidence, timeout, func(oldTs, newTs *types.TipSet) (bool, StateChange, error) {
|
||||||
|
if matchData == nil {
|
||||||
|
return false, matchData, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
d := matchData
|
||||||
|
matchData = nil
|
||||||
|
return true, d, nil
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// create few blocks to make sure nothing get's randomly called
|
||||||
|
|
||||||
|
fcs.advance(0, 4, nil) // H=5
|
||||||
|
require.Equal(t, false, applied)
|
||||||
|
require.Equal(t, false, reverted)
|
||||||
|
|
||||||
|
// create state change (but below confidence threshold)
|
||||||
|
matchData = testStateChange{from: "a", to: "b"}
|
||||||
|
fcs.advance(0, 3, nil)
|
||||||
|
|
||||||
|
require.Equal(t, false, applied)
|
||||||
|
require.Equal(t, false, reverted)
|
||||||
|
|
||||||
|
// create additional block so we are above confidence threshold
|
||||||
|
|
||||||
|
fcs.advance(0, 2, nil) // H=10 (confidence=3, apply)
|
||||||
|
|
||||||
|
require.Equal(t, true, applied)
|
||||||
|
require.Equal(t, false, reverted)
|
||||||
|
applied = false
|
||||||
|
|
||||||
|
// dip below confidence (should not apply again)
|
||||||
|
fcs.advance(2, 2, nil) // H=10 (confidence=3, apply)
|
||||||
|
|
||||||
|
require.Equal(t, false, applied)
|
||||||
|
require.Equal(t, false, reverted)
|
||||||
|
|
||||||
|
// Change happens from 5 -> 6
|
||||||
|
require.Equal(t, abi.ChainEpoch(5), appliedOldTs.Height())
|
||||||
|
require.Equal(t, abi.ChainEpoch(6), appliedNewTs.Height())
|
||||||
|
|
||||||
|
// Actually applied (with confidence) at 9
|
||||||
|
require.Equal(t, abi.ChainEpoch(9), appliedH)
|
||||||
|
|
||||||
|
// Make sure the state change was correctly passed through
|
||||||
|
rcvd := appliedData.(testStateChange)
|
||||||
|
require.Equal(t, "a", rcvd.from)
|
||||||
|
require.Equal(t, "b", rcvd.to)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStateChangedRevert(t *testing.T) {
|
||||||
|
fcs := &fakeCS{
|
||||||
|
t: t,
|
||||||
|
h: 1,
|
||||||
|
|
||||||
|
msgs: map[cid.Cid]fakeMsg{},
|
||||||
|
blkMsgs: map[cid.Cid]cid.Cid{},
|
||||||
|
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
|
||||||
|
}
|
||||||
|
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
|
||||||
|
|
||||||
|
events := NewEvents(context.Background(), fcs)
|
||||||
|
|
||||||
|
more := true
|
||||||
|
var applied, reverted bool
|
||||||
|
var matchData StateChange
|
||||||
|
|
||||||
|
confidence := 1
|
||||||
|
timeout := abi.ChainEpoch(20)
|
||||||
|
|
||||||
|
err := events.StateChanged(func(ts *types.TipSet) (d bool, m bool, e error) {
|
||||||
|
return false, true, nil
|
||||||
|
}, func(oldTs, newTs *types.TipSet, data StateChange, curH abi.ChainEpoch) (bool, error) {
|
||||||
|
require.Equal(t, false, applied)
|
||||||
|
applied = true
|
||||||
|
return more, nil
|
||||||
|
}, func(_ context.Context, ts *types.TipSet) error {
|
||||||
|
reverted = true
|
||||||
|
return nil
|
||||||
|
}, confidence, timeout, func(oldTs, newTs *types.TipSet) (bool, StateChange, error) {
|
||||||
|
if matchData == nil {
|
||||||
|
return false, matchData, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
d := matchData
|
||||||
|
matchData = nil
|
||||||
|
return true, d, nil
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
fcs.advance(0, 2, nil) // H=3
|
||||||
|
|
||||||
|
// Make a state change from TS at height 3 to TS at height 4
|
||||||
|
matchData = testStateChange{from: "a", to: "b"}
|
||||||
|
fcs.advance(0, 1, nil) // H=4
|
||||||
|
|
||||||
|
// Haven't yet reached confidence
|
||||||
|
require.Equal(t, false, applied)
|
||||||
|
require.Equal(t, false, reverted)
|
||||||
|
|
||||||
|
// Advance to reach confidence level
|
||||||
|
fcs.advance(0, 1, nil) // H=5
|
||||||
|
|
||||||
|
// Should now have called the handler
|
||||||
|
require.Equal(t, true, applied)
|
||||||
|
require.Equal(t, false, reverted)
|
||||||
|
applied = false
|
||||||
|
|
||||||
|
// Advance 3 more TS
|
||||||
|
fcs.advance(0, 3, nil) // H=8
|
||||||
|
|
||||||
|
require.Equal(t, false, applied)
|
||||||
|
require.Equal(t, false, reverted)
|
||||||
|
|
||||||
|
// Regress but not so far as to cause a revert
|
||||||
|
fcs.advance(3, 1, nil) // H=6
|
||||||
|
|
||||||
|
require.Equal(t, false, applied)
|
||||||
|
require.Equal(t, false, reverted)
|
||||||
|
|
||||||
|
// Regress back to state where change happened
|
||||||
|
fcs.advance(3, 1, nil) // H=4
|
||||||
|
|
||||||
|
// Expect revert to have happened
|
||||||
|
require.Equal(t, false, applied)
|
||||||
|
require.Equal(t, true, reverted)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStateChangedTimeout(t *testing.T) {
|
||||||
|
fcs := &fakeCS{
|
||||||
|
t: t,
|
||||||
|
h: 1,
|
||||||
|
|
||||||
|
msgs: map[cid.Cid]fakeMsg{},
|
||||||
|
blkMsgs: map[cid.Cid]cid.Cid{},
|
||||||
|
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
|
||||||
|
}
|
||||||
|
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
|
||||||
|
|
||||||
|
events := NewEvents(context.Background(), fcs)
|
||||||
|
|
||||||
|
called := false
|
||||||
|
|
||||||
|
err := events.StateChanged(func(ts *types.TipSet) (d bool, m bool, e error) {
|
||||||
|
return false, true, nil
|
||||||
|
}, func(oldTs, newTs *types.TipSet, data StateChange, curH abi.ChainEpoch) (bool, error) {
|
||||||
|
called = true
|
||||||
|
require.Nil(t, data)
|
||||||
|
require.Equal(t, abi.ChainEpoch(20), newTs.Height())
|
||||||
|
require.Equal(t, abi.ChainEpoch(23), curH)
|
||||||
|
return false, nil
|
||||||
|
}, func(_ context.Context, ts *types.TipSet) error {
|
||||||
|
t.Fatal("revert on timeout")
|
||||||
|
return nil
|
||||||
|
}, 3, 20, func(oldTs, newTs *types.TipSet) (bool, StateChange, error) {
|
||||||
|
return false, nil, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
fcs.advance(0, 21, nil)
|
||||||
|
require.False(t, called)
|
||||||
|
|
||||||
|
fcs.advance(0, 5, nil)
|
||||||
|
require.True(t, called)
|
||||||
|
called = false
|
||||||
|
|
||||||
|
// with check func reporting done
|
||||||
|
|
||||||
|
fcs = &fakeCS{
|
||||||
|
t: t,
|
||||||
|
h: 1,
|
||||||
|
|
||||||
|
msgs: map[cid.Cid]fakeMsg{},
|
||||||
|
blkMsgs: map[cid.Cid]cid.Cid{},
|
||||||
|
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
|
||||||
|
}
|
||||||
|
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
|
||||||
|
|
||||||
|
events = NewEvents(context.Background(), fcs)
|
||||||
|
|
||||||
|
err = events.StateChanged(func(ts *types.TipSet) (d bool, m bool, e error) {
|
||||||
|
return true, true, nil
|
||||||
|
}, func(oldTs, newTs *types.TipSet, data StateChange, curH abi.ChainEpoch) (bool, error) {
|
||||||
|
called = true
|
||||||
|
require.Nil(t, data)
|
||||||
|
require.Equal(t, abi.ChainEpoch(20), newTs.Height())
|
||||||
|
require.Equal(t, abi.ChainEpoch(23), curH)
|
||||||
|
return false, nil
|
||||||
|
}, func(_ context.Context, ts *types.TipSet) error {
|
||||||
|
t.Fatal("revert on timeout")
|
||||||
|
return nil
|
||||||
|
}, 3, 20, func(oldTs, newTs *types.TipSet) (bool, StateChange, error) {
|
||||||
|
return false, nil, nil
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
fcs.advance(0, 21, nil)
|
||||||
|
require.False(t, called)
|
||||||
|
|
||||||
|
fcs.advance(0, 5, nil)
|
||||||
|
require.False(t, called)
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,137 @@
|
|||||||
|
package state
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-amt-ipld/v2"
|
||||||
|
"github.com/filecoin-project/lotus/api/apibstore"
|
||||||
|
"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/market"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
cbor "github.com/ipfs/go-ipld-cbor"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UserData is the data returned from the DiffFunc
|
||||||
|
type UserData interface{}
|
||||||
|
|
||||||
|
// ChainAPI abstracts out calls made by this class to external APIs
|
||||||
|
type ChainAPI interface {
|
||||||
|
apibstore.ChainIO
|
||||||
|
StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StatePredicates has common predicates for responding to state changes
|
||||||
|
type StatePredicates struct {
|
||||||
|
api ChainAPI
|
||||||
|
cst *cbor.BasicIpldStore
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStatePredicates(api ChainAPI) *StatePredicates {
|
||||||
|
return &StatePredicates{
|
||||||
|
api: api,
|
||||||
|
cst: cbor.NewCborStore(apibstore.NewAPIBlockstore(api)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DiffFunc check if there's a change form oldState to newState, and returns
|
||||||
|
// - changed: was there a change
|
||||||
|
// - user: user-defined data representing the state change
|
||||||
|
// - err
|
||||||
|
type DiffFunc func(ctx context.Context, oldState, newState *types.TipSet) (changed bool, user UserData, err error)
|
||||||
|
|
||||||
|
type DiffStateFunc func(ctx context.Context, oldActorStateHead, newActorStateHead cid.Cid) (changed bool, user UserData, err error)
|
||||||
|
|
||||||
|
// OnActorStateChanged calls diffStateFunc when the state changes for the given actor
|
||||||
|
func (sp *StatePredicates) OnActorStateChanged(addr address.Address, diffStateFunc DiffStateFunc) DiffFunc {
|
||||||
|
return func(ctx context.Context, oldState, newState *types.TipSet) (changed bool, user UserData, err error) {
|
||||||
|
oldActor, err := sp.api.StateGetActor(ctx, addr, oldState.Key())
|
||||||
|
if err != nil {
|
||||||
|
return false, nil, err
|
||||||
|
}
|
||||||
|
newActor, err := sp.api.StateGetActor(ctx, addr, newState.Key())
|
||||||
|
if err != nil {
|
||||||
|
return false, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if oldActor.Head.Equals(newActor.Head) {
|
||||||
|
return false, nil, nil
|
||||||
|
}
|
||||||
|
return diffStateFunc(ctx, oldActor.Head, newActor.Head)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type DiffStorageMarketStateFunc func(ctx context.Context, oldState *market.State, newState *market.State) (changed bool, user UserData, err error)
|
||||||
|
|
||||||
|
// OnStorageMarketActorChanged calls diffStorageMarketState when the state changes for the market actor
|
||||||
|
func (sp *StatePredicates) OnStorageMarketActorChanged(diffStorageMarketState DiffStorageMarketStateFunc) DiffFunc {
|
||||||
|
return sp.OnActorStateChanged(builtin.StorageMarketActorAddr, func(ctx context.Context, oldActorStateHead, newActorStateHead cid.Cid) (changed bool, user UserData, err error) {
|
||||||
|
var oldState market.State
|
||||||
|
if err := sp.cst.Get(ctx, oldActorStateHead, &oldState); err != nil {
|
||||||
|
return false, nil, err
|
||||||
|
}
|
||||||
|
var newState market.State
|
||||||
|
if err := sp.cst.Get(ctx, newActorStateHead, &newState); err != nil {
|
||||||
|
return false, nil, err
|
||||||
|
}
|
||||||
|
return diffStorageMarketState(ctx, &oldState, &newState)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type DiffDealStatesFunc func(ctx context.Context, oldDealStateRoot *amt.Root, newDealStateRoot *amt.Root) (changed bool, user UserData, err error)
|
||||||
|
|
||||||
|
// OnDealStateChanged calls diffDealStates when the market state changes
|
||||||
|
func (sp *StatePredicates) OnDealStateChanged(diffDealStates DiffDealStatesFunc) DiffStorageMarketStateFunc {
|
||||||
|
return func(ctx context.Context, oldState *market.State, newState *market.State) (changed bool, user UserData, err error) {
|
||||||
|
if oldState.States.Equals(newState.States) {
|
||||||
|
return false, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
oldRoot, err := amt.LoadAMT(ctx, sp.cst, oldState.States)
|
||||||
|
if err != nil {
|
||||||
|
return false, nil, err
|
||||||
|
}
|
||||||
|
newRoot, err := amt.LoadAMT(ctx, sp.cst, newState.States)
|
||||||
|
if err != nil {
|
||||||
|
return false, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return diffDealStates(ctx, oldRoot, newRoot)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChangedDeals is a set of changes to deal state
|
||||||
|
type ChangedDeals map[abi.DealID]DealStateChange
|
||||||
|
|
||||||
|
// DealStateChange is a change in deal state from -> to
|
||||||
|
type DealStateChange struct {
|
||||||
|
From market.DealState
|
||||||
|
To market.DealState
|
||||||
|
}
|
||||||
|
|
||||||
|
// DealStateChangedForIDs detects changes in the deal state AMT for the given deal IDs
|
||||||
|
func (sp *StatePredicates) DealStateChangedForIDs(dealIds []abi.DealID) DiffDealStatesFunc {
|
||||||
|
return func(ctx context.Context, oldDealStateRoot *amt.Root, newDealStateRoot *amt.Root) (changed bool, user UserData, err error) {
|
||||||
|
changedDeals := make(ChangedDeals)
|
||||||
|
for _, dealID := range dealIds {
|
||||||
|
var oldDeal, newDeal market.DealState
|
||||||
|
err := oldDealStateRoot.Get(ctx, uint64(dealID), &oldDeal)
|
||||||
|
if err != nil {
|
||||||
|
return false, nil, err
|
||||||
|
}
|
||||||
|
err = newDealStateRoot.Get(ctx, uint64(dealID), &newDeal)
|
||||||
|
if err != nil {
|
||||||
|
return false, nil, err
|
||||||
|
}
|
||||||
|
if oldDeal != newDeal {
|
||||||
|
changedDeals[dealID] = DealStateChange{oldDeal, newDeal}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(changedDeals) > 0 {
|
||||||
|
return true, changedDeals, nil
|
||||||
|
}
|
||||||
|
return false, nil, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,201 @@
|
|||||||
|
package state
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||||
|
"github.com/ipfs/go-hamt-ipld"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-amt-ipld/v2"
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/builtin/market"
|
||||||
|
ds "github.com/ipfs/go-datastore"
|
||||||
|
ds_sync "github.com/ipfs/go-datastore/sync"
|
||||||
|
bstore "github.com/ipfs/go-ipfs-blockstore"
|
||||||
|
cbornode "github.com/ipfs/go-ipld-cbor"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||||
|
)
|
||||||
|
|
||||||
|
var dummyCid cid.Cid
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dummyCid, _ = cid.Parse("bafkqaaa")
|
||||||
|
}
|
||||||
|
|
||||||
|
type mockAPI struct {
|
||||||
|
ts map[types.TipSetKey]*types.Actor
|
||||||
|
bs bstore.Blockstore
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMockAPI(bs bstore.Blockstore) *mockAPI {
|
||||||
|
return &mockAPI{
|
||||||
|
bs: bs,
|
||||||
|
ts: make(map[types.TipSetKey]*types.Actor),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockAPI) ChainHasObj(ctx context.Context, c cid.Cid) (bool, error) {
|
||||||
|
return m.bs.Has(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockAPI) ChainReadObj(ctx context.Context, c cid.Cid) ([]byte, error) {
|
||||||
|
blk, err := m.bs.Get(c)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("blockstore get: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return blk.RawData(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockAPI) StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) {
|
||||||
|
return m.ts[tsk], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockAPI) setActor(tsk types.TipSetKey, act *types.Actor) {
|
||||||
|
m.ts[tsk] = act
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPredicates(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
bs := bstore.NewBlockstore(ds_sync.MutexWrap(ds.NewMapDatastore()))
|
||||||
|
store := cbornode.NewCborStore(bs)
|
||||||
|
|
||||||
|
oldDeals := map[abi.DealID]*market.DealState{
|
||||||
|
abi.DealID(1): {
|
||||||
|
SectorStartEpoch: 1,
|
||||||
|
LastUpdatedEpoch: 2,
|
||||||
|
SlashEpoch: 0,
|
||||||
|
},
|
||||||
|
abi.DealID(2): {
|
||||||
|
SectorStartEpoch: 4,
|
||||||
|
LastUpdatedEpoch: 5,
|
||||||
|
SlashEpoch: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
oldStateC := createMarketState(ctx, t, store, oldDeals)
|
||||||
|
|
||||||
|
newDeals := map[abi.DealID]*market.DealState{
|
||||||
|
abi.DealID(1): {
|
||||||
|
SectorStartEpoch: 1,
|
||||||
|
LastUpdatedEpoch: 3,
|
||||||
|
SlashEpoch: 0,
|
||||||
|
},
|
||||||
|
abi.DealID(2): {
|
||||||
|
SectorStartEpoch: 4,
|
||||||
|
LastUpdatedEpoch: 6,
|
||||||
|
SlashEpoch: 6,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
newStateC := createMarketState(ctx, t, store, newDeals)
|
||||||
|
|
||||||
|
miner, err := address.NewFromString("t00")
|
||||||
|
require.NoError(t, err)
|
||||||
|
oldState, err := mockTipset(miner, 1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
newState, err := mockTipset(miner, 2)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
api := newMockAPI(bs)
|
||||||
|
api.setActor(oldState.Key(), &types.Actor{Head: oldStateC})
|
||||||
|
api.setActor(newState.Key(), &types.Actor{Head: newStateC})
|
||||||
|
|
||||||
|
preds := NewStatePredicates(api)
|
||||||
|
|
||||||
|
dealIds := []abi.DealID{abi.DealID(1), abi.DealID(2)}
|
||||||
|
diffFn := preds.OnStorageMarketActorChanged(preds.OnDealStateChanged(preds.DealStateChangedForIDs(dealIds)))
|
||||||
|
|
||||||
|
// Diff a state against itself: expect no change
|
||||||
|
changed, _, err := diffFn(ctx, oldState, oldState)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.False(t, changed)
|
||||||
|
|
||||||
|
// Diff old state against new state
|
||||||
|
changed, val, err := diffFn(ctx, oldState, newState)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, changed)
|
||||||
|
|
||||||
|
changedDeals, ok := val.(ChangedDeals)
|
||||||
|
require.True(t, ok)
|
||||||
|
require.Len(t, changedDeals, 2)
|
||||||
|
require.Contains(t, changedDeals, abi.DealID(1))
|
||||||
|
require.Contains(t, changedDeals, abi.DealID(2))
|
||||||
|
deal1 := changedDeals[abi.DealID(1)]
|
||||||
|
if deal1.From.LastUpdatedEpoch != 2 || deal1.To.LastUpdatedEpoch != 3 {
|
||||||
|
t.Fatal("Unexpected change to LastUpdatedEpoch")
|
||||||
|
}
|
||||||
|
deal2 := changedDeals[abi.DealID(2)]
|
||||||
|
if deal2.From.SlashEpoch != 0 || deal2.To.SlashEpoch != 6 {
|
||||||
|
t.Fatal("Unexpected change to SlashEpoch")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that OnActorStateChanged does not call the callback if the state has not changed
|
||||||
|
mockAddr, err := address.NewFromString("t01")
|
||||||
|
require.NoError(t, err)
|
||||||
|
actorDiffFn := preds.OnActorStateChanged(mockAddr, func(context.Context, cid.Cid, cid.Cid) (bool, UserData, error) {
|
||||||
|
t.Fatal("No state change so this should not be called")
|
||||||
|
return false, nil, nil
|
||||||
|
})
|
||||||
|
changed, _, err = actorDiffFn(ctx, oldState, oldState)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.False(t, changed)
|
||||||
|
|
||||||
|
// Test that OnDealStateChanged does not call the callback if the state has not changed
|
||||||
|
diffDealStateFn := preds.OnDealStateChanged(func(context.Context, *amt.Root, *amt.Root) (bool, UserData, error) {
|
||||||
|
t.Fatal("No state change so this should not be called")
|
||||||
|
return false, nil, nil
|
||||||
|
})
|
||||||
|
marketState := createEmptyMarketState(t, store)
|
||||||
|
changed, _, err = diffDealStateFn(ctx, marketState, marketState)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.False(t, changed)
|
||||||
|
}
|
||||||
|
|
||||||
|
func mockTipset(miner address.Address, timestamp uint64) (*types.TipSet, error) {
|
||||||
|
return types.NewTipSet([]*types.BlockHeader{{
|
||||||
|
Miner: miner,
|
||||||
|
Height: 5,
|
||||||
|
ParentStateRoot: dummyCid,
|
||||||
|
Messages: dummyCid,
|
||||||
|
ParentMessageReceipts: dummyCid,
|
||||||
|
BlockSig: &crypto.Signature{Type: crypto.SigTypeBLS},
|
||||||
|
BLSAggregate: &crypto.Signature{Type: crypto.SigTypeBLS},
|
||||||
|
Timestamp: timestamp,
|
||||||
|
}})
|
||||||
|
}
|
||||||
|
|
||||||
|
func createMarketState(ctx context.Context, t *testing.T, store *cbornode.BasicIpldStore, deals map[abi.DealID]*market.DealState) cid.Cid {
|
||||||
|
rootCid := createAMT(ctx, t, store, deals)
|
||||||
|
|
||||||
|
state := createEmptyMarketState(t, store)
|
||||||
|
state.States = rootCid
|
||||||
|
|
||||||
|
stateC, err := store.Put(ctx, state)
|
||||||
|
require.NoError(t, err)
|
||||||
|
return stateC
|
||||||
|
}
|
||||||
|
|
||||||
|
func createEmptyMarketState(t *testing.T, store *cbornode.BasicIpldStore) *market.State {
|
||||||
|
emptyArrayCid, err := amt.NewAMT(store).Flush(context.TODO())
|
||||||
|
require.NoError(t, err)
|
||||||
|
emptyMap, err := store.Put(context.TODO(), hamt.NewNode(store, hamt.UseTreeBitWidth(5)))
|
||||||
|
require.NoError(t, err)
|
||||||
|
return market.ConstructState(emptyArrayCid, emptyMap, emptyMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createAMT(ctx context.Context, t *testing.T, store *cbornode.BasicIpldStore, deals map[abi.DealID]*market.DealState) cid.Cid {
|
||||||
|
root := amt.NewAMT(store)
|
||||||
|
for dealID, dealState := range deals {
|
||||||
|
err := root.Set(ctx, uint64(dealID), dealState)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
rootCid, err := root.Flush(ctx)
|
||||||
|
require.NoError(t, err)
|
||||||
|
return rootCid
|
||||||
|
}
|
||||||
@@ -8,11 +8,11 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (e *calledEvents) CheckMsg(ctx context.Context, smsg types.ChainMsg, hnd CalledHandler) CheckFunc {
|
func (me *messageEvents) CheckMsg(ctx context.Context, smsg types.ChainMsg, hnd MsgHandler) CheckFunc {
|
||||||
msg := smsg.VMMessage()
|
msg := smsg.VMMessage()
|
||||||
|
|
||||||
return func(ts *types.TipSet) (done bool, more bool, err error) {
|
return func(ts *types.TipSet) (done bool, more bool, err error) {
|
||||||
fa, err := e.cs.StateGetActor(ctx, msg.From, ts.Key())
|
fa, err := me.cs.StateGetActor(ctx, msg.From, ts.Key())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, true, err
|
return false, true, err
|
||||||
}
|
}
|
||||||
@@ -22,7 +22,7 @@ func (e *calledEvents) CheckMsg(ctx context.Context, smsg types.ChainMsg, hnd Ca
|
|||||||
return false, true, nil
|
return false, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
rec, err := e.cs.StateGetReceipt(ctx, smsg.VMMessage().Cid(), ts.Key())
|
rec, err := me.cs.StateGetReceipt(ctx, smsg.VMMessage().Cid(), ts.Key())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, true, xerrors.Errorf("getting receipt in CheckMsg: %w", err)
|
return false, true, xerrors.Errorf("getting receipt in CheckMsg: %w", err)
|
||||||
}
|
}
|
||||||
@@ -33,10 +33,10 @@ func (e *calledEvents) CheckMsg(ctx context.Context, smsg types.ChainMsg, hnd Ca
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *calledEvents) MatchMsg(inmsg *types.Message) MatchFunc {
|
func (me *messageEvents) MatchMsg(inmsg *types.Message) MsgMatchFunc {
|
||||||
return func(msg *types.Message) (bool, error) {
|
return func(msg *types.Message) (bool, error) {
|
||||||
if msg.From == inmsg.From && msg.Nonce == inmsg.Nonce && !inmsg.Equals(msg) {
|
if msg.From == inmsg.From && msg.Nonce == inmsg.Nonce && !inmsg.Equals(msg) {
|
||||||
return false, xerrors.Errorf("matching msg %s from %s, nonce %d: got duplicate origin/nonce msg %s", inmsg.Cid(), inmsg.From, inmsg.Nonce, msg.Nonce)
|
return false, xerrors.Errorf("matching msg %s from %s, nonce %d: got duplicate origin/nonce msg %d", inmsg.Cid(), inmsg.From, inmsg.Nonce, msg.Nonce)
|
||||||
}
|
}
|
||||||
|
|
||||||
return inmsg.Equals(msg), nil
|
return inmsg.Equals(msg), nil
|
||||||
|
|||||||
+14
-19
@@ -45,6 +45,10 @@ var log = logging.Logger("gen")
|
|||||||
|
|
||||||
const msgsPerBlock = 20
|
const msgsPerBlock = 20
|
||||||
|
|
||||||
|
var ValidWpostForTesting = []abi.PoStProof{{
|
||||||
|
ProofBytes: []byte("valid proof"),
|
||||||
|
}}
|
||||||
|
|
||||||
type ChainGen struct {
|
type ChainGen struct {
|
||||||
msgsPerBlock int
|
msgsPerBlock int
|
||||||
|
|
||||||
@@ -89,8 +93,8 @@ func (m mybs) Get(c cid.Cid) (block.Block, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
||||||
saminer.SupportedProofTypes = map[abi.RegisteredProof]struct{}{
|
saminer.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
|
||||||
abi.RegisteredProof_StackedDRG2KiBSeal: {},
|
abi.RegisteredSealProof_StackedDrg2KiBV1: {},
|
||||||
}
|
}
|
||||||
|
|
||||||
mr := repo.NewMemory(nil)
|
mr := repo.NewMemory(nil)
|
||||||
@@ -141,7 +145,7 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
genm1, k1, err := seed.PreSeal(maddr1, abi.RegisteredProof_StackedDRG2KiBPoSt, 0, numSectors, m1temp, []byte("some randomness"), nil)
|
genm1, k1, err := seed.PreSeal(maddr1, abi.RegisteredSealProof_StackedDrg2KiBV1, 0, numSectors, m1temp, []byte("some randomness"), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -153,7 +157,7 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
genm2, k2, err := seed.PreSeal(maddr2, abi.RegisteredProof_StackedDRG2KiBPoSt, 0, numSectors, m2temp, []byte("some randomness"), nil)
|
genm2, k2, err := seed.PreSeal(maddr2, abi.RegisteredSealProof_StackedDrg2KiBV1, 0, numSectors, m2temp, []byte("some randomness"), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -192,7 +196,7 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
|||||||
*genm2,
|
*genm2,
|
||||||
},
|
},
|
||||||
NetworkName: "",
|
NetworkName: "",
|
||||||
Timestamp: uint64(time.Now().Add(-500 * build.BlockDelay * time.Second).Unix()),
|
Timestamp: uint64(time.Now().Add(-500 * time.Duration(build.BlockDelaySecs) * time.Second).Unix()),
|
||||||
}
|
}
|
||||||
|
|
||||||
genb, err := genesis2.MakeGenesisBlock(context.TODO(), bs, sys, tpl)
|
genb, err := genesis2.MakeGenesisBlock(context.TODO(), bs, sys, tpl)
|
||||||
@@ -219,7 +223,7 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
|||||||
miners := []address.Address{maddr1, maddr2}
|
miners := []address.Address{maddr1, maddr2}
|
||||||
|
|
||||||
beac := beacon.NewMockBeacon(time.Second)
|
beac := beacon.NewMockBeacon(time.Second)
|
||||||
//beac, err := drand.NewDrandBeacon(tpl.Timestamp, build.BlockDelay)
|
//beac, err := drand.NewDrandBeacon(tpl.Timestamp, build.BlockDelaySecs)
|
||||||
//if err != nil {
|
//if err != nil {
|
||||||
//return nil, xerrors.Errorf("creating drand beacon: %w", err)
|
//return nil, xerrors.Errorf("creating drand beacon: %w", err)
|
||||||
//}
|
//}
|
||||||
@@ -410,7 +414,7 @@ func (cg *ChainGen) makeBlock(parents *types.TipSet, m address.Address, vrfticke
|
|||||||
if cg.Timestamper != nil {
|
if cg.Timestamper != nil {
|
||||||
ts = cg.Timestamper(parents, height-parents.Height())
|
ts = cg.Timestamper(parents, height-parents.Height())
|
||||||
} else {
|
} else {
|
||||||
ts = parents.MinTimestamp() + uint64((height-parents.Height())*build.BlockDelay)
|
ts = parents.MinTimestamp() + uint64(height-parents.Height())*build.BlockDelaySecs
|
||||||
}
|
}
|
||||||
|
|
||||||
fblk, err := MinerCreateBlock(context.TODO(), cg.sm, cg.w, &api.BlockTemplate{
|
fblk, err := MinerCreateBlock(context.TODO(), cg.sm, cg.w, &api.BlockTemplate{
|
||||||
@@ -431,7 +435,7 @@ func (cg *ChainGen) makeBlock(parents *types.TipSet, m address.Address, vrfticke
|
|||||||
return fblk, err
|
return fblk, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function is awkward. It's used to deal with messages made when
|
// ResyncBankerNonce is used for dealing with messages made when
|
||||||
// simulating forks
|
// simulating forks
|
||||||
func (cg *ChainGen) ResyncBankerNonce(ts *types.TipSet) error {
|
func (cg *ChainGen) ResyncBankerNonce(ts *types.TipSet) error {
|
||||||
act, err := cg.sm.GetActor(cg.banker, ts)
|
act, err := cg.sm.GetActor(cg.banker, ts)
|
||||||
@@ -533,16 +537,7 @@ func (wpp *wppProvider) GenerateCandidates(ctx context.Context, _ abi.PoStRandom
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (wpp *wppProvider) ComputeProof(context.Context, []abi.SectorInfo, abi.PoStRandomness) ([]abi.PoStProof, error) {
|
func (wpp *wppProvider) ComputeProof(context.Context, []abi.SectorInfo, abi.PoStRandomness) ([]abi.PoStProof, error) {
|
||||||
return []abi.PoStProof{{
|
return ValidWpostForTesting, nil
|
||||||
ProofBytes: []byte("valid proof"),
|
|
||||||
}}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type ProofInput struct {
|
|
||||||
sectors []abi.SectorInfo
|
|
||||||
hvrf []byte
|
|
||||||
challengedSectors []uint64
|
|
||||||
vrfout []byte
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsRoundWinner(ctx context.Context, ts *types.TipSet, round abi.ChainEpoch,
|
func IsRoundWinner(ctx context.Context, ts *types.TipSet, round abi.ChainEpoch,
|
||||||
@@ -618,6 +613,6 @@ func (m genFakeVerifier) VerifyWindowPoSt(ctx context.Context, info abi.WindowPo
|
|||||||
panic("not supported")
|
panic("not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m genFakeVerifier) GenerateWinningPoStSectorChallenge(ctx context.Context, proof abi.RegisteredProof, id abi.ActorID, randomness abi.PoStRandomness, u uint64) ([]uint64, error) {
|
func (m genFakeVerifier) GenerateWinningPoStSectorChallenge(ctx context.Context, proof abi.RegisteredPoStProof, id abi.ActorID, randomness abi.PoStRandomness, u uint64) ([]uint64, error) {
|
||||||
panic("not supported")
|
panic("not supported")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
miner.SupportedProofTypes = map[abi.RegisteredProof]struct{}{
|
miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
|
||||||
abi.RegisteredProof_StackedDRG2KiBSeal: {},
|
abi.RegisteredSealProof_StackedDrg2KiBV1: {},
|
||||||
}
|
}
|
||||||
power.ConsensusMinerMinPower = big.NewInt(2048)
|
power.ConsensusMinerMinPower = big.NewInt(2048)
|
||||||
verifreg.MinVerifiedDealSize = big.NewInt(256)
|
verifreg.MinVerifiedDealSize = big.NewInt(256)
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
|||||||
constructorParams := &power.CreateMinerParams{
|
constructorParams := &power.CreateMinerParams{
|
||||||
Owner: m.Worker,
|
Owner: m.Worker,
|
||||||
Worker: m.Worker,
|
Worker: m.Worker,
|
||||||
Peer: m.PeerId,
|
Peer: []byte(m.PeerId),
|
||||||
SealProofType: spt,
|
SealProofType: spt,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,12 +204,12 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
|||||||
{
|
{
|
||||||
newSectorInfo := &miner.SectorOnChainInfo{
|
newSectorInfo := &miner.SectorOnChainInfo{
|
||||||
Info: miner.SectorPreCommitInfo{
|
Info: miner.SectorPreCommitInfo{
|
||||||
RegisteredProof: preseal.ProofType,
|
SealProof: preseal.ProofType,
|
||||||
SectorNumber: preseal.SectorID,
|
SectorNumber: preseal.SectorID,
|
||||||
SealedCID: preseal.CommR,
|
SealedCID: preseal.CommR,
|
||||||
SealRandEpoch: 0,
|
SealRandEpoch: 0,
|
||||||
DealIDs: []abi.DealID{dealIDs[pi]},
|
DealIDs: []abi.DealID{dealIDs[pi]},
|
||||||
Expiration: preseal.Deal.EndEpoch,
|
Expiration: preseal.Deal.EndEpoch,
|
||||||
},
|
},
|
||||||
ActivationEpoch: 0,
|
ActivationEpoch: 0,
|
||||||
DealWeight: dealWeight.DealWeight,
|
DealWeight: dealWeight.DealWeight,
|
||||||
@@ -242,6 +242,9 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
|||||||
st.TotalQualityAdjPower = big.Sub(st.TotalQualityAdjPower, big.NewInt(1))
|
st.TotalQualityAdjPower = big.Sub(st.TotalQualityAdjPower, big.NewInt(1))
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
return cid.Undef, xerrors.Errorf("mutating state: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
c, err := vm.Flush(ctx)
|
c, err := vm.Flush(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -150,6 +150,17 @@ func aggregateSignatures(sigs []crypto.Signature) (*crypto.Signature, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
aggSig := bls.Aggregate(blsSigs)
|
aggSig := bls.Aggregate(blsSigs)
|
||||||
|
if aggSig == nil {
|
||||||
|
if len(sigs) > 0 {
|
||||||
|
return nil, xerrors.Errorf("bls.Aggregate returned nil with %d signatures", len(sigs))
|
||||||
|
}
|
||||||
|
|
||||||
|
return &crypto.Signature{
|
||||||
|
Type: crypto.SigTypeBLS,
|
||||||
|
Data: new(bls.Signature)[:],
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
return &crypto.Signature{
|
return &crypto.Signature{
|
||||||
Type: crypto.SigTypeBLS,
|
Type: crypto.SigTypeBLS,
|
||||||
Data: aggSig[:],
|
Data: aggSig[:],
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName) (*Messa
|
|||||||
|
|
||||||
mp := &MessagePool{
|
mp := &MessagePool{
|
||||||
closer: make(chan struct{}),
|
closer: make(chan struct{}),
|
||||||
repubTk: time.NewTicker(build.BlockDelay * 10 * time.Second),
|
repubTk: time.NewTicker(time.Duration(build.BlockDelaySecs) * 10 * time.Second),
|
||||||
localAddrs: make(map[address.Address]struct{}),
|
localAddrs: make(map[address.Address]struct{}),
|
||||||
pending: make(map[address.Address]*msgSet),
|
pending: make(map[address.Address]*msgSet),
|
||||||
minGasPrice: types.NewInt(0),
|
minGasPrice: types.NewInt(0),
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import (
|
|||||||
"github.com/ipfs/go-datastore"
|
"github.com/ipfs/go-datastore"
|
||||||
)
|
)
|
||||||
|
|
||||||
type testMpoolApi struct {
|
type testMpoolAPI struct {
|
||||||
cb func(rev, app []*types.TipSet) error
|
cb func(rev, app []*types.TipSet) error
|
||||||
|
|
||||||
bmsgs map[cid.Cid][]*types.SignedMessage
|
bmsgs map[cid.Cid][]*types.SignedMessage
|
||||||
@@ -25,68 +25,68 @@ type testMpoolApi struct {
|
|||||||
tipsets []*types.TipSet
|
tipsets []*types.TipSet
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestMpoolApi() *testMpoolApi {
|
func newTestMpoolAPI() *testMpoolAPI {
|
||||||
return &testMpoolApi{
|
return &testMpoolAPI{
|
||||||
bmsgs: make(map[cid.Cid][]*types.SignedMessage),
|
bmsgs: make(map[cid.Cid][]*types.SignedMessage),
|
||||||
statenonce: make(map[address.Address]uint64),
|
statenonce: make(map[address.Address]uint64),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tma *testMpoolApi) applyBlock(t *testing.T, b *types.BlockHeader) {
|
func (tma *testMpoolAPI) applyBlock(t *testing.T, b *types.BlockHeader) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
if err := tma.cb(nil, []*types.TipSet{mock.TipSet(b)}); err != nil {
|
if err := tma.cb(nil, []*types.TipSet{mock.TipSet(b)}); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tma *testMpoolApi) revertBlock(t *testing.T, b *types.BlockHeader) {
|
func (tma *testMpoolAPI) revertBlock(t *testing.T, b *types.BlockHeader) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
if err := tma.cb([]*types.TipSet{mock.TipSet(b)}, nil); err != nil {
|
if err := tma.cb([]*types.TipSet{mock.TipSet(b)}, nil); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tma *testMpoolApi) setStateNonce(addr address.Address, v uint64) {
|
func (tma *testMpoolAPI) setStateNonce(addr address.Address, v uint64) {
|
||||||
tma.statenonce[addr] = v
|
tma.statenonce[addr] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tma *testMpoolApi) setBlockMessages(h *types.BlockHeader, msgs ...*types.SignedMessage) {
|
func (tma *testMpoolAPI) setBlockMessages(h *types.BlockHeader, msgs ...*types.SignedMessage) {
|
||||||
tma.bmsgs[h.Cid()] = msgs
|
tma.bmsgs[h.Cid()] = msgs
|
||||||
tma.tipsets = append(tma.tipsets, mock.TipSet(h))
|
tma.tipsets = append(tma.tipsets, mock.TipSet(h))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tma *testMpoolApi) SubscribeHeadChanges(cb func(rev, app []*types.TipSet) error) *types.TipSet {
|
func (tma *testMpoolAPI) SubscribeHeadChanges(cb func(rev, app []*types.TipSet) error) *types.TipSet {
|
||||||
tma.cb = cb
|
tma.cb = cb
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tma *testMpoolApi) PutMessage(m types.ChainMsg) (cid.Cid, error) {
|
func (tma *testMpoolAPI) PutMessage(m types.ChainMsg) (cid.Cid, error) {
|
||||||
return cid.Undef, nil
|
return cid.Undef, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tma *testMpoolApi) PubSubPublish(string, []byte) error {
|
func (tma *testMpoolAPI) PubSubPublish(string, []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tma *testMpoolApi) StateGetActor(addr address.Address, ts *types.TipSet) (*types.Actor, error) {
|
func (tma *testMpoolAPI) StateGetActor(addr address.Address, ts *types.TipSet) (*types.Actor, error) {
|
||||||
return &types.Actor{
|
return &types.Actor{
|
||||||
Nonce: tma.statenonce[addr],
|
Nonce: tma.statenonce[addr],
|
||||||
Balance: types.NewInt(90000000),
|
Balance: types.NewInt(90000000),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tma *testMpoolApi) StateAccountKey(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
|
func (tma *testMpoolAPI) StateAccountKey(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
|
||||||
if addr.Protocol() != address.BLS && addr.Protocol() != address.SECP256K1 {
|
if addr.Protocol() != address.BLS && addr.Protocol() != address.SECP256K1 {
|
||||||
return address.Undef, fmt.Errorf("given address was not a key addr")
|
return address.Undef, fmt.Errorf("given address was not a key addr")
|
||||||
}
|
}
|
||||||
return addr, nil
|
return addr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tma *testMpoolApi) MessagesForBlock(h *types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error) {
|
func (tma *testMpoolAPI) MessagesForBlock(h *types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error) {
|
||||||
return nil, tma.bmsgs[h.Cid()], nil
|
return nil, tma.bmsgs[h.Cid()], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tma *testMpoolApi) MessagesForTipset(ts *types.TipSet) ([]types.ChainMsg, error) {
|
func (tma *testMpoolAPI) MessagesForTipset(ts *types.TipSet) ([]types.ChainMsg, error) {
|
||||||
if len(ts.Blocks()) != 1 {
|
if len(ts.Blocks()) != 1 {
|
||||||
panic("cant deal with multiblock tipsets in this test")
|
panic("cant deal with multiblock tipsets in this test")
|
||||||
}
|
}
|
||||||
@@ -108,7 +108,7 @@ func (tma *testMpoolApi) MessagesForTipset(ts *types.TipSet) ([]types.ChainMsg,
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tma *testMpoolApi) LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error) {
|
func (tma *testMpoolAPI) LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error) {
|
||||||
for _, ts := range tma.tipsets {
|
for _, ts := range tma.tipsets {
|
||||||
if types.CidArrsEqual(tsk.Cids(), ts.Cids()) {
|
if types.CidArrsEqual(tsk.Cids(), ts.Cids()) {
|
||||||
return ts, nil
|
return ts, nil
|
||||||
@@ -138,7 +138,7 @@ func mustAdd(t *testing.T, mp *MessagePool, msg *types.SignedMessage) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMessagePool(t *testing.T) {
|
func TestMessagePool(t *testing.T) {
|
||||||
tma := newTestMpoolApi()
|
tma := newTestMpoolAPI()
|
||||||
|
|
||||||
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -179,7 +179,7 @@ func TestMessagePool(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRevertMessages(t *testing.T) {
|
func TestRevertMessages(t *testing.T) {
|
||||||
tma := newTestMpoolApi()
|
tma := newTestMpoolAPI()
|
||||||
|
|
||||||
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import (
|
|||||||
|
|
||||||
var log = logging.Logger("statetree")
|
var log = logging.Logger("statetree")
|
||||||
|
|
||||||
// Stores actors state by their ID.
|
// StateTree stores actors state by their ID.
|
||||||
type StateTree struct {
|
type StateTree struct {
|
||||||
root *hamt.Node
|
root *hamt.Node
|
||||||
Store cbor.IpldStore
|
Store cbor.IpldStore
|
||||||
@@ -149,7 +149,7 @@ func (st *StateTree) SetActor(addr address.Address, act *types.Actor) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// `LookupID` gets the ID address of this actor's `addr` stored in the `InitActor`.
|
// LookupID gets the ID address of this actor's `addr` stored in the `InitActor`.
|
||||||
func (st *StateTree) LookupID(addr address.Address) (address.Address, error) {
|
func (st *StateTree) LookupID(addr address.Address) (address.Address, error) {
|
||||||
if addr.Protocol() == address.ID {
|
if addr.Protocol() == address.ID {
|
||||||
return addr, nil
|
return addr, nil
|
||||||
|
|||||||
+5
-5
@@ -62,11 +62,11 @@ func (sm *StateManager) CallRaw(ctx context.Context, msg *types.Message, bstate
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &api.InvocResult{
|
return &api.InvocResult{
|
||||||
Msg: msg,
|
Msg: msg,
|
||||||
MsgRct: &ret.MessageReceipt,
|
MsgRct: &ret.MessageReceipt,
|
||||||
InternalExecutions: ret.InternalExecutions,
|
ExecutionTrace: ret.ExecutionTrace,
|
||||||
Error: errs,
|
Error: errs,
|
||||||
Duration: ret.Duration,
|
Duration: ret.Duration,
|
||||||
}, nil
|
}, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
miner.SupportedProofTypes = map[abi.RegisteredProof]struct{}{
|
miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
|
||||||
abi.RegisteredProof_StackedDRG2KiBSeal: {},
|
abi.RegisteredSealProof_StackedDrg2KiBV1: {},
|
||||||
}
|
}
|
||||||
power.ConsensusMinerMinPower = big.NewInt(2048)
|
power.ConsensusMinerMinPower = big.NewInt(2048)
|
||||||
verifreg.MinVerifiedDealSize = big.NewInt(256)
|
verifreg.MinVerifiedDealSize = big.NewInt(256)
|
||||||
|
|||||||
+49
-19
@@ -121,10 +121,10 @@ func (sm *StateManager) ExecutionTrace(ctx context.Context, ts *types.TipSet) (c
|
|||||||
var trace []*api.InvocResult
|
var trace []*api.InvocResult
|
||||||
st, _, err := sm.computeTipSetState(ctx, ts.Blocks(), func(mcid cid.Cid, msg *types.Message, ret *vm.ApplyRet) error {
|
st, _, err := sm.computeTipSetState(ctx, ts.Blocks(), func(mcid cid.Cid, msg *types.Message, ret *vm.ApplyRet) error {
|
||||||
ir := &api.InvocResult{
|
ir := &api.InvocResult{
|
||||||
Msg: msg,
|
Msg: msg,
|
||||||
MsgRct: &ret.MessageReceipt,
|
MsgRct: &ret.MessageReceipt,
|
||||||
InternalExecutions: ret.InternalExecutions,
|
ExecutionTrace: ret.ExecutionTrace,
|
||||||
Duration: ret.Duration,
|
Duration: ret.Duration,
|
||||||
}
|
}
|
||||||
if ret.ActorErr != nil {
|
if ret.ActorErr != nil {
|
||||||
ir.Error = ret.ActorErr.Error()
|
ir.Error = ret.ActorErr.Error()
|
||||||
@@ -184,10 +184,9 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, pstate cid.Cid, bms []B
|
|||||||
|
|
||||||
var err error
|
var err error
|
||||||
params, err := actors.SerializeParams(&reward.AwardBlockRewardParams{
|
params, err := actors.SerializeParams(&reward.AwardBlockRewardParams{
|
||||||
Miner: b.Miner,
|
Miner: b.Miner,
|
||||||
Penalty: penalty,
|
Penalty: penalty,
|
||||||
GasReward: gasReward,
|
GasReward: gasReward,
|
||||||
TicketCount: 1, // TODO: no longer need ticket count here.
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, cid.Undef, xerrors.Errorf("failed to serialize award params: %w", err)
|
return cid.Undef, cid.Undef, xerrors.Errorf("failed to serialize award params: %w", err)
|
||||||
@@ -326,7 +325,7 @@ func (sm *StateManager) computeTipSetState(ctx context.Context, blks []*types.Bl
|
|||||||
blkmsgs = append(blkmsgs, bm)
|
blkmsgs = append(blkmsgs, bm)
|
||||||
}
|
}
|
||||||
|
|
||||||
return sm.ApplyBlocks(ctx, pstate, blkmsgs, abi.ChainEpoch(blks[0].Height), r, cb)
|
return sm.ApplyBlocks(ctx, pstate, blkmsgs, blks[0].Height, r, cb)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *StateManager) parentState(ts *types.TipSet) cid.Cid {
|
func (sm *StateManager) parentState(ts *types.TipSet) cid.Cid {
|
||||||
@@ -405,8 +404,8 @@ func (sm *StateManager) LoadActorStateRaw(ctx context.Context, a address.Address
|
|||||||
return act, nil
|
return act, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Similar to `vm.ResolveToKeyAddr` but does not allow `Actor` type of addresses. Uses the `TipSet` `ts`
|
// ResolveToKeyAddress is similar to `vm.ResolveToKeyAddr` but does not allow `Actor` type of addresses.
|
||||||
// to generate the VM state.
|
// Uses the `TipSet` `ts` to generate the VM state.
|
||||||
func (sm *StateManager) ResolveToKeyAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
|
func (sm *StateManager) ResolveToKeyAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
|
||||||
switch addr.Protocol() {
|
switch addr.Protocol() {
|
||||||
case address.BLS, address.SECP256K1:
|
case address.BLS, address.SECP256K1:
|
||||||
@@ -480,7 +479,10 @@ func (sm *StateManager) GetReceipt(ctx context.Context, msg cid.Cid, ts *types.T
|
|||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid) (*types.TipSet, *types.MessageReceipt, error) {
|
// WaitForMessage blocks until a message appears on chain. It looks backwards in the chain to see if this has already
|
||||||
|
// happened. It guarantees that the message has been on chain for at least confidence epochs without being reverted
|
||||||
|
// before returning.
|
||||||
|
func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid, confidence uint64) (*types.TipSet, *types.MessageReceipt, error) {
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
@@ -528,6 +530,11 @@ func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid) (*type
|
|||||||
close(backSearchWait)
|
close(backSearchWait)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
var candidateTs *types.TipSet
|
||||||
|
var candidateRcp *types.MessageReceipt
|
||||||
|
heightOfHead := head[0].Val.Height()
|
||||||
|
reverts := map[types.TipSetKey]bool{}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case notif, ok := <-tsub:
|
case notif, ok := <-tsub:
|
||||||
@@ -537,21 +544,44 @@ func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid) (*type
|
|||||||
for _, val := range notif {
|
for _, val := range notif {
|
||||||
switch val.Type {
|
switch val.Type {
|
||||||
case store.HCRevert:
|
case store.HCRevert:
|
||||||
continue
|
if val.Val.Equals(candidateTs) {
|
||||||
|
candidateTs = nil
|
||||||
|
candidateRcp = nil
|
||||||
|
}
|
||||||
|
if backSearchWait != nil {
|
||||||
|
reverts[val.Val.Key()] = true
|
||||||
|
}
|
||||||
case store.HCApply:
|
case store.HCApply:
|
||||||
|
if candidateTs != nil && val.Val.Height() >= candidateTs.Height()+abi.ChainEpoch(confidence) {
|
||||||
|
return candidateTs, candidateRcp, nil
|
||||||
|
}
|
||||||
r, err := sm.tipsetExecutedMessage(val.Val, mcid, msg.VMMessage())
|
r, err := sm.tipsetExecutedMessage(val.Val, mcid, msg.VMMessage())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
if r != nil {
|
if r != nil {
|
||||||
return val.Val, r, nil
|
if confidence == 0 {
|
||||||
|
return val.Val, r, err
|
||||||
|
}
|
||||||
|
candidateTs = val.Val
|
||||||
|
candidateRcp = r
|
||||||
}
|
}
|
||||||
|
heightOfHead = val.Val.Height()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case <-backSearchWait:
|
case <-backSearchWait:
|
||||||
if backTs != nil {
|
// check if we found the message in the chain and that is hasn't been reverted since we started searching
|
||||||
return backTs, backRcp, nil
|
if backTs != nil && !reverts[backTs.Key()] {
|
||||||
|
// if head is at or past confidence interval, return immediately
|
||||||
|
if heightOfHead >= backTs.Height()+abi.ChainEpoch(confidence) {
|
||||||
|
return backTs, backRcp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for confidence interval
|
||||||
|
candidateTs = backTs
|
||||||
|
candidateRcp = backRcp
|
||||||
}
|
}
|
||||||
|
reverts = nil
|
||||||
backSearchWait = nil
|
backSearchWait = nil
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return nil, nil, ctx.Err()
|
return nil, nil, ctx.Err()
|
||||||
@@ -610,9 +640,9 @@ func (sm *StateManager) searchBackForMsg(ctx context.Context, from *types.TipSet
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if act.Nonce < m.VMMessage().Nonce {
|
// we either have no messages from the sender, or the latest message we found has a lower nonce than the one being searched for,
|
||||||
// nonce on chain is before message nonce we're looking for, its
|
// either way, no reason to lookback, it ain't there
|
||||||
// not going to be here
|
if act.Nonce == 0 || act.Nonce < m.VMMessage().Nonce {
|
||||||
return nil, nil, nil
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+51
-12
@@ -13,6 +13,7 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
amt "github.com/filecoin-project/go-amt-ipld/v2"
|
amt "github.com/filecoin-project/go-amt-ipld/v2"
|
||||||
|
"github.com/filecoin-project/go-bitfield"
|
||||||
"github.com/filecoin-project/sector-storage/ffiwrapper"
|
"github.com/filecoin-project/sector-storage/ffiwrapper"
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
@@ -173,13 +174,34 @@ func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *S
|
|||||||
return nil, xerrors.Errorf("(get sectors) failed to load miner actor state: %w", err)
|
return nil, xerrors.Errorf("(get sectors) failed to load miner actor state: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Optimization: we could avoid loaditg the whole proving set here if we had AMT.GetNth with bitfield filtering
|
cst := cbor.NewCborStore(sm.cs.Blockstore())
|
||||||
sectorSet, err := GetProvingSetRaw(ctx, sm, mas)
|
var deadlines miner.Deadlines
|
||||||
if err != nil {
|
if err := cst.Get(ctx, mas.Deadlines, &deadlines); err != nil {
|
||||||
return nil, xerrors.Errorf("getting proving set: %w", err)
|
return nil, xerrors.Errorf("failed to load deadlines: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(sectorSet) == 0 {
|
notProving, err := abi.BitFieldUnion(mas.Faults, mas.Recoveries)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to union faults and recoveries: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
allSectors, err := bitfield.MultiMerge(append(deadlines.Due[:], mas.NewSectors)...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("merging deadline bitfields failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
provingSectors, err := bitfield.SubtractBitField(allSectors, notProving)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to subtract non-proving sectors from set: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
numProvSect, err := provingSectors.Count()
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to count bits: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(review): is this right? feels fishy to me
|
||||||
|
if numProvSect == 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,17 +220,34 @@ func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *S
|
|||||||
return nil, xerrors.Errorf("getting miner ID: %w", err)
|
return nil, xerrors.Errorf("getting miner ID: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ids, err := pv.GenerateWinningPoStSectorChallenge(ctx, wpt, abi.ActorID(mid), rand, uint64(len(sectorSet)))
|
ids, err := pv.GenerateWinningPoStSectorChallenge(ctx, wpt, abi.ActorID(mid), rand, numProvSect)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("generating winning post challenges: %w", err)
|
return nil, xerrors.Errorf("generating winning post challenges: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sectors, err := provingSectors.All(miner.SectorsMax)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to enumerate all sector IDs: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sectorAmt, err := amt.LoadAMT(ctx, cst, mas.Sectors)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to load sectors amt: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
out := make([]abi.SectorInfo, len(ids))
|
out := make([]abi.SectorInfo, len(ids))
|
||||||
for i, n := range ids {
|
for i, n := range ids {
|
||||||
|
sid := sectors[n]
|
||||||
|
|
||||||
|
var sinfo miner.SectorOnChainInfo
|
||||||
|
if err := sectorAmt.Get(ctx, sid, &sinfo); err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to get sector %d: %w", sid, err)
|
||||||
|
}
|
||||||
|
|
||||||
out[i] = abi.SectorInfo{
|
out[i] = abi.SectorInfo{
|
||||||
RegisteredProof: wpt,
|
SealProof: spt,
|
||||||
SectorNumber: sectorSet[n].ID,
|
SectorNumber: sinfo.Info.SectorNumber,
|
||||||
SealedCID: sectorSet[n].Info.Info.SealedCID,
|
SealedCID: sinfo.Info.SealedCID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,7 +325,7 @@ func GetMinerRecoveries(ctx context.Context, sm *StateManager, ts *types.TipSet,
|
|||||||
return mas.Recoveries, nil
|
return mas.Recoveries, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetStorageDeal(ctx context.Context, sm *StateManager, dealId abi.DealID, ts *types.TipSet) (*api.MarketDeal, error) {
|
func GetStorageDeal(ctx context.Context, sm *StateManager, dealID abi.DealID, ts *types.TipSet) (*api.MarketDeal, error) {
|
||||||
var state market.State
|
var state market.State
|
||||||
if _, err := sm.LoadActorState(ctx, builtin.StorageMarketActorAddr, &state, ts); err != nil {
|
if _, err := sm.LoadActorState(ctx, builtin.StorageMarketActorAddr, &state, ts); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -298,7 +337,7 @@ func GetStorageDeal(ctx context.Context, sm *StateManager, dealId abi.DealID, ts
|
|||||||
}
|
}
|
||||||
|
|
||||||
var dp market.DealProposal
|
var dp market.DealProposal
|
||||||
if err := da.Get(ctx, uint64(dealId), &dp); err != nil {
|
if err := da.Get(ctx, uint64(dealID), &dp); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,7 +346,7 @@ func GetStorageDeal(ctx context.Context, sm *StateManager, dealId abi.DealID, ts
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
st, found, err := sa.Get(dealId)
|
st, found, err := sa.Get(dealID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,8 +32,11 @@ func (fts *FullTipSet) Cids() []cid.Cid {
|
|||||||
return cids
|
return cids
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TipSet returns a narrower view of this FullTipSet elliding the block
|
||||||
|
// messages.
|
||||||
func (fts *FullTipSet) TipSet() *types.TipSet {
|
func (fts *FullTipSet) TipSet() *types.TipSet {
|
||||||
if fts.tipset != nil {
|
if fts.tipset != nil {
|
||||||
|
// FIXME: fts.tipset is actually never set. Should it memoize?
|
||||||
return fts.tipset
|
return fts.tipset
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,161 @@
|
|||||||
|
package store
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"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"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ChainIndex struct {
|
||||||
|
skipCache *lru.ARCCache
|
||||||
|
|
||||||
|
loadTipSet loadTipSetFunc
|
||||||
|
|
||||||
|
skipLength abi.ChainEpoch
|
||||||
|
}
|
||||||
|
type loadTipSetFunc func(types.TipSetKey) (*types.TipSet, error)
|
||||||
|
|
||||||
|
func NewChainIndex(lts loadTipSetFunc) *ChainIndex {
|
||||||
|
sc, _ := lru.NewARC(8192)
|
||||||
|
return &ChainIndex{
|
||||||
|
skipCache: sc,
|
||||||
|
loadTipSet: lts,
|
||||||
|
skipLength: 20,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type lbEntry struct {
|
||||||
|
ts *types.TipSet
|
||||||
|
parentHeight abi.ChainEpoch
|
||||||
|
targetHeight abi.ChainEpoch
|
||||||
|
target types.TipSetKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ci *ChainIndex) GetTipsetByHeight(_ context.Context, from *types.TipSet, to abi.ChainEpoch) (*types.TipSet, error) {
|
||||||
|
if from.Height()-to <= ci.skipLength {
|
||||||
|
return ci.walkBack(from, to)
|
||||||
|
}
|
||||||
|
|
||||||
|
rounded, err := ci.roundDown(from)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
cur := rounded.Key()
|
||||||
|
for {
|
||||||
|
cval, ok := ci.skipCache.Get(cur)
|
||||||
|
if !ok {
|
||||||
|
fc, err := ci.fillCache(cur)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cval = fc
|
||||||
|
}
|
||||||
|
|
||||||
|
lbe := cval.(*lbEntry)
|
||||||
|
if lbe.ts.Height() == to || lbe.parentHeight < to {
|
||||||
|
return lbe.ts, nil
|
||||||
|
} else if to > lbe.targetHeight {
|
||||||
|
return ci.walkBack(lbe.ts, to)
|
||||||
|
}
|
||||||
|
|
||||||
|
cur = lbe.target
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ci *ChainIndex) GetTipsetByHeightWithoutCache(from *types.TipSet, to abi.ChainEpoch) (*types.TipSet, error) {
|
||||||
|
return ci.walkBack(from, to)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ci *ChainIndex) fillCache(tsk types.TipSetKey) (*lbEntry, error) {
|
||||||
|
ts, err := ci.loadTipSet(tsk)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if ts.Height() == 0 {
|
||||||
|
return &lbEntry{
|
||||||
|
ts: ts,
|
||||||
|
parentHeight: 0,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// will either be equal to ts.Height, or at least > ts.Parent.Height()
|
||||||
|
rheight := ci.roundHeight(ts.Height())
|
||||||
|
|
||||||
|
parent, err := ci.loadTipSet(ts.Parents())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rheight -= ci.skipLength
|
||||||
|
|
||||||
|
var skipTarget *types.TipSet
|
||||||
|
if parent.Height() < rheight {
|
||||||
|
skipTarget = parent
|
||||||
|
} else {
|
||||||
|
skipTarget, err = ci.walkBack(parent, rheight)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("fillCache walkback: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lbe := &lbEntry{
|
||||||
|
ts: ts,
|
||||||
|
parentHeight: parent.Height(),
|
||||||
|
targetHeight: skipTarget.Height(),
|
||||||
|
target: skipTarget.Key(),
|
||||||
|
}
|
||||||
|
ci.skipCache.Add(tsk, lbe)
|
||||||
|
|
||||||
|
return lbe, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// floors to nearest skipLength multiple
|
||||||
|
func (ci *ChainIndex) roundHeight(h abi.ChainEpoch) abi.ChainEpoch {
|
||||||
|
return (h / ci.skipLength) * ci.skipLength
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ci *ChainIndex) roundDown(ts *types.TipSet) (*types.TipSet, error) {
|
||||||
|
target := ci.roundHeight(ts.Height())
|
||||||
|
|
||||||
|
rounded, err := ci.walkBack(ts, target)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rounded, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ci *ChainIndex) walkBack(from *types.TipSet, to abi.ChainEpoch) (*types.TipSet, error) {
|
||||||
|
if to > from.Height() {
|
||||||
|
return nil, xerrors.Errorf("looking for tipset with height greater than start point")
|
||||||
|
}
|
||||||
|
|
||||||
|
if to == from.Height() {
|
||||||
|
return from, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ts := from
|
||||||
|
|
||||||
|
for {
|
||||||
|
pts, err := ci.loadTipSet(ts.Parents())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if to > pts.Height() {
|
||||||
|
// in case pts is lower than the epoch we're looking for (null blocks)
|
||||||
|
// return a tipset above that height
|
||||||
|
return ts, nil
|
||||||
|
}
|
||||||
|
if to == pts.Height() {
|
||||||
|
return pts, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ts = pts
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package store_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"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/specs-actors/actors/abi"
|
||||||
|
datastore "github.com/ipfs/go-datastore"
|
||||||
|
syncds "github.com/ipfs/go-datastore/sync"
|
||||||
|
blockstore "github.com/ipfs/go-ipfs-blockstore"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIndexSeeks(t *testing.T) {
|
||||||
|
cg, err := gen.NewGenerator()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
gencar, err := cg.GenesisCar()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
gen := cg.Genesis()
|
||||||
|
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
|
nbs := blockstore.NewBlockstore(syncds.MutexWrap(datastore.NewMapDatastore()))
|
||||||
|
cs := store.NewChainStore(nbs, syncds.MutexWrap(datastore.NewMapDatastore()), nil)
|
||||||
|
|
||||||
|
_, err = cs.Import(bytes.NewReader(gencar))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cur := mock.TipSet(gen)
|
||||||
|
if err := cs.PutTipSet(ctx, mock.TipSet(gen)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
cs.SetGenesis(gen)
|
||||||
|
|
||||||
|
// Put 113 blocks from genesis
|
||||||
|
for i := 0; i < 113; i++ {
|
||||||
|
nextts := mock.TipSet(mock.MkBlock(cur, 1, 1))
|
||||||
|
|
||||||
|
if err := cs.PutTipSet(ctx, nextts); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
cur = nextts
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put 50 null epochs + 1 block
|
||||||
|
skip := mock.MkBlock(cur, 1, 1)
|
||||||
|
skip.Height += 50
|
||||||
|
|
||||||
|
skipts := mock.TipSet(skip)
|
||||||
|
|
||||||
|
if err := cs.PutTipSet(ctx, skipts); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ts, err := cs.GetTipsetByHeight(ctx, skip.Height-10, skipts, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
assert.Equal(t, abi.ChainEpoch(164), ts.Height())
|
||||||
|
|
||||||
|
for i := 0; i <= 113; i++ {
|
||||||
|
ts3, err := cs.GetTipsetByHeight(ctx, abi.ChainEpoch(i), skipts, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
assert.Equal(t, abi.ChainEpoch(i), ts3.Height())
|
||||||
|
}
|
||||||
|
}
|
||||||
+97
-48
@@ -18,7 +18,6 @@ import (
|
|||||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/build"
|
|
||||||
"github.com/filecoin-project/lotus/chain/state"
|
"github.com/filecoin-project/lotus/chain/state"
|
||||||
"github.com/filecoin-project/lotus/chain/vm"
|
"github.com/filecoin-project/lotus/chain/vm"
|
||||||
"github.com/filecoin-project/lotus/metrics"
|
"github.com/filecoin-project/lotus/metrics"
|
||||||
@@ -48,7 +47,20 @@ import (
|
|||||||
var log = logging.Logger("chainstore")
|
var log = logging.Logger("chainstore")
|
||||||
|
|
||||||
var chainHeadKey = dstore.NewKey("head")
|
var chainHeadKey = dstore.NewKey("head")
|
||||||
|
var blockValidationCacheKeyPrefix = dstore.NewKey("blockValidation")
|
||||||
|
|
||||||
|
// ReorgNotifee represents a callback that gets called upon reorgs.
|
||||||
|
type ReorgNotifee func(rev, app []*types.TipSet) error
|
||||||
|
|
||||||
|
// ChainStore is the main point of access to chain data.
|
||||||
|
//
|
||||||
|
// Raw chain data is stored in the Blockstore, with relevant markers (genesis,
|
||||||
|
// latest head tipset references) being tracked in the Datastore (key-value
|
||||||
|
// store).
|
||||||
|
//
|
||||||
|
// To alleviate disk access, the ChainStore has two ARC caches:
|
||||||
|
// 1. a tipset cache
|
||||||
|
// 2. a block => messages references cache.
|
||||||
type ChainStore struct {
|
type ChainStore struct {
|
||||||
bs bstore.Blockstore
|
bs bstore.Blockstore
|
||||||
ds dstore.Datastore
|
ds dstore.Datastore
|
||||||
@@ -62,8 +74,10 @@ type ChainStore struct {
|
|||||||
tstLk sync.Mutex
|
tstLk sync.Mutex
|
||||||
tipsets map[abi.ChainEpoch][]cid.Cid
|
tipsets map[abi.ChainEpoch][]cid.Cid
|
||||||
|
|
||||||
reorgCh chan<- reorg
|
cindex *ChainIndex
|
||||||
headChangeNotifs []func(rev, app []*types.TipSet) error
|
|
||||||
|
reorgCh chan<- reorg
|
||||||
|
reorgNotifeeCh chan ReorgNotifee
|
||||||
|
|
||||||
mmCache *lru.ARCCache
|
mmCache *lru.ARCCache
|
||||||
tsCache *lru.ARCCache
|
tsCache *lru.ARCCache
|
||||||
@@ -84,7 +98,9 @@ func NewChainStore(bs bstore.Blockstore, ds dstore.Batching, vmcalls runtime.Sys
|
|||||||
vmcalls: vmcalls,
|
vmcalls: vmcalls,
|
||||||
}
|
}
|
||||||
|
|
||||||
cs.reorgCh = cs.reorgWorker(context.TODO())
|
ci := NewChainIndex(cs.LoadTipSet)
|
||||||
|
|
||||||
|
cs.cindex = ci
|
||||||
|
|
||||||
hcnf := func(rev, app []*types.TipSet) error {
|
hcnf := func(rev, app []*types.TipSet) error {
|
||||||
cs.pubLk.Lock()
|
cs.pubLk.Lock()
|
||||||
@@ -117,7 +133,8 @@ func NewChainStore(bs bstore.Blockstore, ds dstore.Batching, vmcalls runtime.Sys
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
cs.headChangeNotifs = append(cs.headChangeNotifs, hcnf, hcmetric)
|
cs.reorgNotifeeCh = make(chan ReorgNotifee)
|
||||||
|
cs.reorgCh = cs.reorgWorker(context.TODO(), []ReorgNotifee{hcnf, hcmetric})
|
||||||
|
|
||||||
return cs
|
return cs
|
||||||
}
|
}
|
||||||
@@ -206,8 +223,24 @@ func (cs *ChainStore) SubHeadChanges(ctx context.Context) chan []*api.HeadChange
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs *ChainStore) SubscribeHeadChanges(f func(rev, app []*types.TipSet) error) {
|
func (cs *ChainStore) SubscribeHeadChanges(f ReorgNotifee) {
|
||||||
cs.headChangeNotifs = append(cs.headChangeNotifs, f)
|
cs.reorgNotifeeCh <- f
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cs *ChainStore) IsBlockValidated(ctx context.Context, blkid cid.Cid) (bool, error) {
|
||||||
|
key := blockValidationCacheKeyPrefix.Instance(blkid.String())
|
||||||
|
|
||||||
|
return cs.ds.Has(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cs *ChainStore) MarkBlockAsValidated(ctx context.Context, blkid cid.Cid) error {
|
||||||
|
key := blockValidationCacheKeyPrefix.Instance(blkid.String())
|
||||||
|
|
||||||
|
if err := cs.ds.Put(key, []byte{0}); err != nil {
|
||||||
|
return xerrors.Errorf("cache block validation: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs *ChainStore) SetGenesis(b *types.BlockHeader) error {
|
func (cs *ChainStore) SetGenesis(b *types.BlockHeader) error {
|
||||||
@@ -242,6 +275,9 @@ func (cs *ChainStore) PutTipSet(ctx context.Context, ts *types.TipSet) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MaybeTakeHeavierTipSet evaluates the incoming tipset and locks it in our
|
||||||
|
// internal state as our new head, if and only if it is heavier than the current
|
||||||
|
// head.
|
||||||
func (cs *ChainStore) MaybeTakeHeavierTipSet(ctx context.Context, ts *types.TipSet) error {
|
func (cs *ChainStore) MaybeTakeHeavierTipSet(ctx context.Context, ts *types.TipSet) error {
|
||||||
cs.heaviestLk.Lock()
|
cs.heaviestLk.Lock()
|
||||||
defer cs.heaviestLk.Unlock()
|
defer cs.heaviestLk.Unlock()
|
||||||
@@ -268,13 +304,19 @@ type reorg struct {
|
|||||||
new *types.TipSet
|
new *types.TipSet
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs *ChainStore) reorgWorker(ctx context.Context) chan<- reorg {
|
func (cs *ChainStore) reorgWorker(ctx context.Context, initialNotifees []ReorgNotifee) chan<- reorg {
|
||||||
out := make(chan reorg, 32)
|
out := make(chan reorg, 32)
|
||||||
|
notifees := make([]ReorgNotifee, len(initialNotifees))
|
||||||
|
copy(notifees, initialNotifees)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer log.Warn("reorgWorker quit")
|
defer log.Warn("reorgWorker quit")
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
|
case n := <-cs.reorgNotifeeCh:
|
||||||
|
notifees = append(notifees, n)
|
||||||
|
|
||||||
case r := <-out:
|
case r := <-out:
|
||||||
revert, apply, err := cs.ReorgOps(r.old, r.new)
|
revert, apply, err := cs.ReorgOps(r.old, r.new)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -288,7 +330,7 @@ func (cs *ChainStore) reorgWorker(ctx context.Context) chan<- reorg {
|
|||||||
apply[i], apply[opp] = apply[opp], apply[i]
|
apply[i], apply[opp] = apply[opp], apply[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, hcf := range cs.headChangeNotifs {
|
for _, hcf := range notifees {
|
||||||
if err := hcf(revert, apply); err != nil {
|
if err := hcf(revert, apply); err != nil {
|
||||||
log.Error("head change func errored (BAD): ", err)
|
log.Error("head change func errored (BAD): ", err)
|
||||||
}
|
}
|
||||||
@@ -301,6 +343,9 @@ func (cs *ChainStore) reorgWorker(ctx context.Context) chan<- reorg {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// takeHeaviestTipSet actually sets the incoming tipset as our head both in
|
||||||
|
// memory and in the ChainStore. It also sends a notification to deliver to
|
||||||
|
// ReorgNotifees.
|
||||||
func (cs *ChainStore) takeHeaviestTipSet(ctx context.Context, ts *types.TipSet) error {
|
func (cs *ChainStore) takeHeaviestTipSet(ctx context.Context, ts *types.TipSet) error {
|
||||||
_, span := trace.StartSpan(ctx, "takeHeaviestTipSet")
|
_, span := trace.StartSpan(ctx, "takeHeaviestTipSet")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
@@ -338,6 +383,7 @@ func (cs *ChainStore) SetHead(ts *types.TipSet) error {
|
|||||||
return cs.takeHeaviestTipSet(context.TODO(), ts)
|
return cs.takeHeaviestTipSet(context.TODO(), ts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Contains returns whether our BlockStore has all blocks in the supplied TipSet.
|
||||||
func (cs *ChainStore) Contains(ts *types.TipSet) (bool, error) {
|
func (cs *ChainStore) Contains(ts *types.TipSet) (bool, error) {
|
||||||
for _, c := range ts.Cids() {
|
for _, c := range ts.Cids() {
|
||||||
has, err := cs.bs.Has(c)
|
has, err := cs.bs.Has(c)
|
||||||
@@ -352,6 +398,8 @@ func (cs *ChainStore) Contains(ts *types.TipSet) (bool, error) {
|
|||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetBlock fetches a BlockHeader with the supplied CID. It returns
|
||||||
|
// blockstore.ErrNotFound if the block was not found in the BlockStore.
|
||||||
func (cs *ChainStore) GetBlock(c cid.Cid) (*types.BlockHeader, error) {
|
func (cs *ChainStore) GetBlock(c cid.Cid) (*types.BlockHeader, error) {
|
||||||
sb, err := cs.bs.Get(c)
|
sb, err := cs.bs.Get(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -387,7 +435,7 @@ func (cs *ChainStore) LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error) {
|
|||||||
return ts, nil
|
return ts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns true if 'a' is an ancestor of 'b'
|
// IsAncestorOf returns true if 'a' is an ancestor of 'b'
|
||||||
func (cs *ChainStore) IsAncestorOf(a, b *types.TipSet) (bool, error) {
|
func (cs *ChainStore) IsAncestorOf(a, b *types.TipSet) (bool, error) {
|
||||||
if b.Height() <= a.Height() {
|
if b.Height() <= a.Height() {
|
||||||
return false, nil
|
return false, nil
|
||||||
@@ -444,6 +492,7 @@ func (cs *ChainStore) ReorgOps(a, b *types.TipSet) ([]*types.TipSet, []*types.Ti
|
|||||||
return leftChain, rightChain, nil
|
return leftChain, rightChain, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetHeaviestTipSet returns the current heaviest tipset known (i.e. our head).
|
||||||
func (cs *ChainStore) GetHeaviestTipSet() *types.TipSet {
|
func (cs *ChainStore) GetHeaviestTipSet() *types.TipSet {
|
||||||
cs.heaviestLk.Lock()
|
cs.heaviestLk.Lock()
|
||||||
defer cs.heaviestLk.Unlock()
|
defer cs.heaviestLk.Unlock()
|
||||||
@@ -910,30 +959,35 @@ func DrawRandomness(rbase []byte, pers crypto.DomainSeparationTag, round abi.Cha
|
|||||||
return h.Sum(nil), nil
|
return h.Sum(nil), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs *ChainStore) GetRandomness(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) (out []byte, err error) {
|
func (cs *ChainStore) GetRandomness(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||||
_, span := trace.StartSpan(ctx, "store.GetRandomness")
|
_, span := trace.StartSpan(ctx, "store.GetRandomness")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
span.AddAttributes(trace.Int64Attribute("round", int64(round)))
|
span.AddAttributes(trace.Int64Attribute("round", int64(round)))
|
||||||
|
|
||||||
//defer func() {
|
ts, err := cs.LoadTipSet(types.NewTipSetKey(blks...))
|
||||||
//log.Infof("getRand %v %d %d %x -> %x", blks, pers, round, entropy, out)
|
if err != nil {
|
||||||
//}()
|
return nil, err
|
||||||
for {
|
|
||||||
nts, err := cs.LoadTipSet(types.NewTipSetKey(blks...))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
mtb := nts.MinTicketBlock()
|
|
||||||
|
|
||||||
// if at (or just past -- for null epochs) appropriate epoch
|
|
||||||
// or at genesis (works for negative epochs)
|
|
||||||
if nts.Height() <= round || mtb.Height == 0 {
|
|
||||||
return DrawRandomness(nts.MinTicketBlock().Ticket.VRFProof, pers, round, entropy)
|
|
||||||
}
|
|
||||||
|
|
||||||
blks = mtb.Parents
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if round > ts.Height() {
|
||||||
|
return nil, xerrors.Errorf("cannot draw randomness from the future")
|
||||||
|
}
|
||||||
|
|
||||||
|
searchHeight := round
|
||||||
|
if searchHeight < 0 {
|
||||||
|
searchHeight = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
randTs, err := cs.GetTipsetByHeight(ctx, searchHeight, ts, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
mtb := randTs.MinTicketBlock()
|
||||||
|
|
||||||
|
// if at (or just past -- for null epochs) appropriate epoch
|
||||||
|
// or at genesis (works for negative epochs)
|
||||||
|
return DrawRandomness(mtb.Ticket.VRFProof, pers, round, entropy)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTipsetByHeight returns the tipset on the chain behind 'ts' at the given
|
// GetTipsetByHeight returns the tipset on the chain behind 'ts' at the given
|
||||||
@@ -946,35 +1000,31 @@ func (cs *ChainStore) GetTipsetByHeight(ctx context.Context, h abi.ChainEpoch, t
|
|||||||
}
|
}
|
||||||
|
|
||||||
if h > ts.Height() {
|
if h > ts.Height() {
|
||||||
return nil, xerrors.Errorf("looking for tipset with height less than start point")
|
return nil, xerrors.Errorf("looking for tipset with height greater than start point")
|
||||||
}
|
}
|
||||||
|
|
||||||
if h == ts.Height() {
|
if h == ts.Height() {
|
||||||
return ts, nil
|
return ts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if ts.Height()-h > build.ForkLengthThreshold {
|
lbts, err := cs.cindex.GetTipsetByHeight(ctx, ts, h)
|
||||||
log.Warnf("expensive call to GetTipsetByHeight, seeking %d levels", ts.Height()-h)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
if lbts.Height() < h {
|
||||||
pts, err := cs.LoadTipSet(ts.Parents())
|
log.Warnf("chain index returned the wrong tipset at height %d, using slow retrieval", h)
|
||||||
|
lbts, err = cs.cindex.GetTipsetByHeightWithoutCache(ts, h)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if h > pts.Height() {
|
|
||||||
if prev {
|
|
||||||
return pts, nil
|
|
||||||
}
|
|
||||||
return ts, nil
|
|
||||||
}
|
|
||||||
if h == pts.Height() {
|
|
||||||
return pts, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
ts = pts
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if lbts.Height() == h || !prev {
|
||||||
|
return lbts, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return cs.LoadTipSet(lbts.Parents())
|
||||||
}
|
}
|
||||||
|
|
||||||
func recurseLinks(bs blockstore.Blockstore, root cid.Cid, in []cid.Cid) ([]cid.Cid, error) {
|
func recurseLinks(bs blockstore.Blockstore, root cid.Cid, in []cid.Cid) ([]cid.Cid, error) {
|
||||||
@@ -1154,7 +1204,6 @@ func (cr *chainRand) GetRandomness(ctx context.Context, pers crypto.DomainSepara
|
|||||||
func (cs *ChainStore) GetTipSetFromKey(tsk types.TipSetKey) (*types.TipSet, error) {
|
func (cs *ChainStore) GetTipSetFromKey(tsk types.TipSetKey) (*types.TipSet, error) {
|
||||||
if tsk.IsEmpty() {
|
if tsk.IsEmpty() {
|
||||||
return cs.GetHeaviestTipSet(), nil
|
return cs.GetHeaviestTipSet(), nil
|
||||||
} else {
|
|
||||||
return cs.LoadTipSet(tsk)
|
|
||||||
}
|
}
|
||||||
|
return cs.LoadTipSet(tsk)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
miner.SupportedProofTypes = map[abi.RegisteredProof]struct{}{
|
miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
|
||||||
abi.RegisteredProof_StackedDRG2KiBSeal: {},
|
abi.RegisteredSealProof_StackedDrg2KiBV1: {},
|
||||||
}
|
}
|
||||||
power.ConsensusMinerMinPower = big.NewInt(2048)
|
power.ConsensusMinerMinPower = big.NewInt(2048)
|
||||||
verifreg.MinVerifiedDealSize = big.NewInt(256)
|
verifreg.MinVerifiedDealSize = big.NewInt(256)
|
||||||
|
|||||||
@@ -57,12 +57,9 @@ func HandleIncomingBlocks(ctx context.Context, bsub *pubsub.Subscription, s *cha
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint:golint
|
src := msg.GetFrom()
|
||||||
src := peer.ID(msg.GetFrom())
|
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
log.Infof("New block over pubsub: %s", blk.Cid())
|
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
log.Debug("about to fetch messages for block from pubsub")
|
log.Debug("about to fetch messages for block from pubsub")
|
||||||
bmsgs, err := s.Bsync.FetchMessagesByCids(context.TODO(), blk.BlsMessages)
|
bmsgs, err := s.Bsync.FetchMessagesByCids(context.TODO(), blk.BlsMessages)
|
||||||
@@ -146,8 +143,7 @@ func (bv *BlockValidator) Validate(ctx context.Context, pid peer.ID, msg *pubsub
|
|||||||
// track validation time
|
// track validation time
|
||||||
begin := time.Now()
|
begin := time.Now()
|
||||||
defer func() {
|
defer func() {
|
||||||
end := time.Now()
|
log.Debugf("block validation time: %s", time.Since(begin))
|
||||||
log.Infof("block validation time: %s", end.Sub(begin))
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
stats.Record(ctx, metrics.BlockReceived.M(1))
|
stats.Record(ctx, metrics.BlockReceived.M(1))
|
||||||
@@ -207,7 +203,7 @@ func (bv *BlockValidator) Validate(ctx context.Context, pid peer.ID, msg *pubsub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = sigs.CheckBlockSignature(blk.Header, ctx, key)
|
err = sigs.CheckBlockSignature(ctx, blk.Header, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("block signature verification failed: %s", err)
|
log.Errorf("block signature verification failed: %s", err)
|
||||||
recordFailure("signature_verification_failed")
|
recordFailure("signature_verification_failed")
|
||||||
|
|||||||
+209
-42
@@ -8,7 +8,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Gurpartap/async"
|
"github.com/Gurpartap/async"
|
||||||
@@ -50,10 +49,37 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/metrics"
|
"github.com/filecoin-project/lotus/metrics"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Blocks that are more than MaxHeightDrift epochs above
|
||||||
|
//the theoretical max height based on systime are quickly rejected
|
||||||
|
const MaxHeightDrift = 5
|
||||||
|
|
||||||
var log = logging.Logger("chain")
|
var log = logging.Logger("chain")
|
||||||
|
|
||||||
var LocalIncoming = "incoming"
|
var LocalIncoming = "incoming"
|
||||||
|
|
||||||
|
// Syncer is in charge of running the chain synchronization logic. As such, it
|
||||||
|
// is tasked with these functions, amongst others:
|
||||||
|
//
|
||||||
|
// * Fast-forwards the chain as it learns of new TipSets from the network via
|
||||||
|
// the SyncManager.
|
||||||
|
// * Applies the fork choice rule to select the correct side when confronted
|
||||||
|
// with a fork in the network.
|
||||||
|
// * Requests block headers and messages from other peers when not available
|
||||||
|
// in our BlockStore.
|
||||||
|
// * Tracks blocks marked as bad in a cache.
|
||||||
|
// * Keeps the BlockStore and ChainStore consistent with our view of the world,
|
||||||
|
// the latter of which in turn informs other components when a reorg has been
|
||||||
|
// committed.
|
||||||
|
//
|
||||||
|
// The Syncer does not run workers itself. It's mainly concerned with
|
||||||
|
// ensuring a consistent state of chain consensus. The reactive and network-
|
||||||
|
// interfacing processes are part of other components, such as the SyncManager
|
||||||
|
// (which owns the sync scheduler and sync workers), BlockSync, the HELLO
|
||||||
|
// protocol, and the gossipsub block propagation layer.
|
||||||
|
//
|
||||||
|
// {hint/concept} The fork-choice rule as it currently stands is: "pick the
|
||||||
|
// chain with the heaviest weight, so long as it hasn’t deviated one finality
|
||||||
|
// threshold from our head (900 epochs, parameter determined by spec-actors)".
|
||||||
type Syncer struct {
|
type Syncer struct {
|
||||||
// The interface for accessing and putting tipsets into local storage
|
// The interface for accessing and putting tipsets into local storage
|
||||||
store *store.ChainStore
|
store *store.ChainStore
|
||||||
@@ -86,6 +112,7 @@ type Syncer struct {
|
|||||||
verifier ffiwrapper.Verifier
|
verifier ffiwrapper.Verifier
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewSyncer creates a new Syncer object.
|
||||||
func NewSyncer(sm *stmgr.StateManager, bsync *blocksync.BlockSync, connmgr connmgr.ConnManager, self peer.ID, beacon beacon.RandomBeacon, verifier ffiwrapper.Verifier) (*Syncer, error) {
|
func NewSyncer(sm *stmgr.StateManager, bsync *blocksync.BlockSync, connmgr connmgr.ConnManager, self peer.ID, beacon beacon.RandomBeacon, verifier ffiwrapper.Verifier) (*Syncer, error) {
|
||||||
gen, err := sm.ChainStore().GetGenesis()
|
gen, err := sm.ChainStore().GetGenesis()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -134,6 +161,11 @@ func (syncer *Syncer) InformNewHead(from peer.ID, fts *store.FullTipSet) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if syncer.IsEpochBeyondCurrMax(fts.TipSet().Height()) {
|
||||||
|
log.Errorf("Received block with impossibly large height %d", fts.TipSet().Height())
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
for _, b := range fts.Blocks {
|
for _, b := range fts.Blocks {
|
||||||
if reason, ok := syncer.bad.Has(b.Cid()); ok {
|
if reason, ok := syncer.bad.Has(b.Cid()); ok {
|
||||||
log.Warnf("InformNewHead called on block marked as bad: %s (reason: %s)", b.Cid(), reason)
|
log.Warnf("InformNewHead called on block marked as bad: %s (reason: %s)", b.Cid(), reason)
|
||||||
@@ -183,6 +215,11 @@ func (syncer *Syncer) InformNewHead(from peer.ID, fts *store.FullTipSet) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IncomingBlocks spawns a goroutine that subscribes to the local eventbus to
|
||||||
|
// receive new block headers as they arrive from the network, and sends them to
|
||||||
|
// the returned channel.
|
||||||
|
//
|
||||||
|
// These blocks have not necessarily been incorporated to our view of the chain.
|
||||||
func (syncer *Syncer) IncomingBlocks(ctx context.Context) (<-chan *types.BlockHeader, error) {
|
func (syncer *Syncer) IncomingBlocks(ctx context.Context) (<-chan *types.BlockHeader, error) {
|
||||||
sub := syncer.incoming.Sub(LocalIncoming)
|
sub := syncer.incoming.Sub(LocalIncoming)
|
||||||
out := make(chan *types.BlockHeader, 10)
|
out := make(chan *types.BlockHeader, 10)
|
||||||
@@ -210,11 +247,15 @@ func (syncer *Syncer) IncomingBlocks(ctx context.Context) (<-chan *types.BlockHe
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ValidateMsgMeta performs structural and content hash validation of the
|
||||||
|
// messages within this block. If validation passes, it stores the messages in
|
||||||
|
// the underlying IPLD block store.
|
||||||
func (syncer *Syncer) ValidateMsgMeta(fblk *types.FullBlock) error {
|
func (syncer *Syncer) ValidateMsgMeta(fblk *types.FullBlock) error {
|
||||||
if msgc := len(fblk.BlsMessages) + len(fblk.SecpkMessages); msgc > build.BlockMessageLimit {
|
if msgc := len(fblk.BlsMessages) + len(fblk.SecpkMessages); msgc > build.BlockMessageLimit {
|
||||||
return xerrors.Errorf("block %s has too many messages (%d)", fblk.Header.Cid(), msgc)
|
return xerrors.Errorf("block %s has too many messages (%d)", fblk.Header.Cid(), msgc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Collect the CIDs of both types of messages separately: BLS and Secpk.
|
||||||
var bcids, scids []cbg.CBORMarshaler
|
var bcids, scids []cbg.CBORMarshaler
|
||||||
for _, m := range fblk.BlsMessages {
|
for _, m := range fblk.BlsMessages {
|
||||||
c := cbg.CborCid(m.Cid())
|
c := cbg.CborCid(m.Cid())
|
||||||
@@ -232,11 +273,14 @@ func (syncer *Syncer) ValidateMsgMeta(fblk *types.FullBlock) error {
|
|||||||
blockstore := syncer.store.Blockstore()
|
blockstore := syncer.store.Blockstore()
|
||||||
|
|
||||||
bs := cbor.NewCborStore(blockstore)
|
bs := cbor.NewCborStore(blockstore)
|
||||||
|
|
||||||
|
// Compute the root CID of the combined message trie.
|
||||||
smroot, err := computeMsgMeta(bs, bcids, scids)
|
smroot, err := computeMsgMeta(bs, bcids, scids)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("validating msgmeta, compute failed: %w", err)
|
return xerrors.Errorf("validating msgmeta, compute failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check that the message trie root matches with what's in the block.
|
||||||
if fblk.Header.Messages != smroot {
|
if fblk.Header.Messages != smroot {
|
||||||
return xerrors.Errorf("messages in full block did not match msgmeta root in header (%s != %s)", fblk.Header.Messages, smroot)
|
return xerrors.Errorf("messages in full block did not match msgmeta root in header (%s != %s)", fblk.Header.Messages, smroot)
|
||||||
}
|
}
|
||||||
@@ -346,6 +390,8 @@ func zipTipSetAndMessages(bs cbor.IpldStore, ts *types.TipSet, allbmsgs []*types
|
|||||||
return fts, nil
|
return fts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// computeMsgMeta computes the root CID of the combined arrays of message CIDs
|
||||||
|
// of both types (BLS and Secpk).
|
||||||
func computeMsgMeta(bs cbor.IpldStore, bmsgCids, smsgCids []cbg.CBORMarshaler) (cid.Cid, error) {
|
func computeMsgMeta(bs cbor.IpldStore, bmsgCids, smsgCids []cbg.CBORMarshaler) (cid.Cid, error) {
|
||||||
ctx := context.TODO()
|
ctx := context.TODO()
|
||||||
bmroot, err := amt.FromArray(ctx, bs, bmsgCids)
|
bmroot, err := amt.FromArray(ctx, bs, bmsgCids)
|
||||||
@@ -369,14 +415,24 @@ func computeMsgMeta(bs cbor.IpldStore, bmsgCids, smsgCids []cbg.CBORMarshaler) (
|
|||||||
return mrcid, nil
|
return mrcid, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FetchTipSet tries to load the provided tipset from the store, and falls back
|
||||||
|
// to the network (BlockSync) by querying the supplied peer if not found
|
||||||
|
// locally.
|
||||||
|
//
|
||||||
|
// {hint/usage} This is used from the HELLO protocol, to fetch the greeting
|
||||||
|
// peer's heaviest tipset if we don't have it.
|
||||||
func (syncer *Syncer) FetchTipSet(ctx context.Context, p peer.ID, tsk types.TipSetKey) (*store.FullTipSet, error) {
|
func (syncer *Syncer) FetchTipSet(ctx context.Context, p peer.ID, tsk types.TipSetKey) (*store.FullTipSet, error) {
|
||||||
if fts, err := syncer.tryLoadFullTipSet(tsk); err == nil {
|
if fts, err := syncer.tryLoadFullTipSet(tsk); err == nil {
|
||||||
return fts, nil
|
return fts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fall back to the network.
|
||||||
return syncer.Bsync.GetFullTipSet(ctx, p, tsk)
|
return syncer.Bsync.GetFullTipSet(ctx, p, tsk)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tryLoadFullTipSet queries the tipset in the ChainStore, and returns a full
|
||||||
|
// representation of it containing FullBlocks. If ALL blocks are not found
|
||||||
|
// locally, it errors entirely with blockstore.ErrNotFound.
|
||||||
func (syncer *Syncer) tryLoadFullTipSet(tsk types.TipSetKey) (*store.FullTipSet, error) {
|
func (syncer *Syncer) tryLoadFullTipSet(tsk types.TipSetKey) (*store.FullTipSet, error) {
|
||||||
ts, err := syncer.store.LoadTipSet(tsk)
|
ts, err := syncer.store.LoadTipSet(tsk)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -401,6 +457,12 @@ func (syncer *Syncer) tryLoadFullTipSet(tsk types.TipSetKey) (*store.FullTipSet,
|
|||||||
return fts, nil
|
return fts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sync tries to advance our view of the chain to `maybeHead`. It does nothing
|
||||||
|
// if our current head is heavier than the requested tipset, or if we're already
|
||||||
|
// at the requested head, or if the head is the genesis.
|
||||||
|
//
|
||||||
|
// Most of the heavy-lifting logic happens in syncer#collectChain. Refer to the
|
||||||
|
// godocs on that method for a more detailed view.
|
||||||
func (syncer *Syncer) Sync(ctx context.Context, maybeHead *types.TipSet) error {
|
func (syncer *Syncer) Sync(ctx context.Context, maybeHead *types.TipSet) error {
|
||||||
ctx, span := trace.StartSpan(ctx, "chain.Sync")
|
ctx, span := trace.StartSpan(ctx, "chain.Sync")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
@@ -429,6 +491,8 @@ func (syncer *Syncer) Sync(ctx context.Context, maybeHead *types.TipSet) error {
|
|||||||
return xerrors.Errorf("collectChain failed: %w", err)
|
return xerrors.Errorf("collectChain failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// At this point we have accepted and synced to the new `maybeHead`
|
||||||
|
// (`StageSyncComplete`).
|
||||||
if err := syncer.store.PutTipSet(ctx, maybeHead); err != nil {
|
if err := syncer.store.PutTipSet(ctx, maybeHead); err != nil {
|
||||||
span.AddAttributes(trace.StringAttribute("put_error", err.Error()))
|
span.AddAttributes(trace.StringAttribute("put_error", err.Error()))
|
||||||
span.SetStatus(trace.Status{
|
span.SetStatus(trace.Status{
|
||||||
@@ -465,16 +529,27 @@ func (syncer *Syncer) ValidateTipSet(ctx context.Context, fts *store.FullTipSet)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var futures []async.ErrorFuture
|
||||||
for _, b := range fts.Blocks {
|
for _, b := range fts.Blocks {
|
||||||
if err := syncer.ValidateBlock(ctx, b); err != nil {
|
b := b // rebind to a scoped variable
|
||||||
if isPermanent(err) {
|
|
||||||
syncer.bad.Add(b.Cid(), err.Error())
|
|
||||||
}
|
|
||||||
return xerrors.Errorf("validating block %s: %w", b.Cid(), err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := syncer.sm.ChainStore().AddToTipSetTracker(b.Header); err != nil {
|
futures = append(futures, async.Err(func() error {
|
||||||
return xerrors.Errorf("failed to add validated header to tipset tracker: %w", err)
|
if err := syncer.ValidateBlock(ctx, b); err != nil {
|
||||||
|
if isPermanent(err) {
|
||||||
|
syncer.bad.Add(b.Cid(), err.Error())
|
||||||
|
}
|
||||||
|
return xerrors.Errorf("validating block %s: %w", b.Cid(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := syncer.sm.ChainStore().AddToTipSetTracker(b.Header); err != nil {
|
||||||
|
return xerrors.Errorf("failed to add validated header to tipset tracker: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
for _, f := range futures {
|
||||||
|
if err := f.AwaitContext(ctx); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -526,10 +601,36 @@ func blockSanityChecks(h *types.BlockHeader) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should match up with 'Semantical Validation' in validation.md in the spec
|
// ValidateBlock should match up with 'Semantical Validation' in validation.md in the spec
|
||||||
func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) error {
|
func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (err error) {
|
||||||
|
defer func() {
|
||||||
|
// b.Cid() could panic for empty blocks that are used in tests.
|
||||||
|
if rerr := recover(); rerr != nil {
|
||||||
|
err = xerrors.Errorf("validate block panic: %w", rerr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
isValidated, err := syncer.store.IsBlockValidated(ctx, b.Cid())
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("check block validation cache %s: %w", b.Cid(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if isValidated {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
validationStart := time.Now()
|
||||||
|
defer func() {
|
||||||
|
dur := time.Since(validationStart)
|
||||||
|
durMilli := dur.Seconds() * float64(1000)
|
||||||
|
stats.Record(ctx, metrics.BlockValidationDurationMilliseconds.M(durMilli))
|
||||||
|
log.Infow("block validation", "took", dur, "height", b.Header.Height)
|
||||||
|
}()
|
||||||
|
|
||||||
ctx, span := trace.StartSpan(ctx, "validateBlock")
|
ctx, span := trace.StartSpan(ctx, "validateBlock")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
if build.InsecurePoStValidation {
|
if build.InsecurePoStValidation {
|
||||||
log.Warn("insecure test validation is enabled, if you see this outside of a test, it is a severe bug!")
|
log.Warn("insecure test validation is enabled, if you see this outside of a test, it is a severe bug!")
|
||||||
}
|
}
|
||||||
@@ -565,18 +666,18 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
|
|||||||
// fast checks first
|
// fast checks first
|
||||||
|
|
||||||
now := uint64(time.Now().Unix())
|
now := uint64(time.Now().Unix())
|
||||||
if h.Timestamp > now+build.AllowableClockDrift {
|
if h.Timestamp > now+build.AllowableClockDriftSecs {
|
||||||
return xerrors.Errorf("block was from the future (now=%d, blk=%d): %w", now, h.Timestamp, ErrTemporal)
|
return xerrors.Errorf("block was from the future (now=%d, blk=%d): %w", now, h.Timestamp, ErrTemporal)
|
||||||
}
|
}
|
||||||
if h.Timestamp > now {
|
if h.Timestamp > now {
|
||||||
log.Warn("Got block from the future, but within threshold", h.Timestamp, time.Now().Unix())
|
log.Warn("Got block from the future, but within threshold", h.Timestamp, time.Now().Unix())
|
||||||
}
|
}
|
||||||
|
|
||||||
if h.Timestamp < baseTs.MinTimestamp()+(build.BlockDelay*uint64(h.Height-baseTs.Height())) {
|
if h.Timestamp < baseTs.MinTimestamp()+(build.BlockDelaySecs*uint64(h.Height-baseTs.Height())) {
|
||||||
log.Warn("timestamp funtimes: ", h.Timestamp, baseTs.MinTimestamp(), h.Height, baseTs.Height())
|
log.Warn("timestamp funtimes: ", h.Timestamp, baseTs.MinTimestamp(), h.Height, baseTs.Height())
|
||||||
diff := (baseTs.MinTimestamp() + (build.BlockDelay * uint64(h.Height-baseTs.Height()))) - h.Timestamp
|
diff := (baseTs.MinTimestamp() + (build.BlockDelaySecs * uint64(h.Height-baseTs.Height()))) - h.Timestamp
|
||||||
|
|
||||||
return xerrors.Errorf("block was generated too soon (h.ts:%d < base.mints:%d + BLOCK_DELAY:%d * deltaH:%d; diff %d)", h.Timestamp, baseTs.MinTimestamp(), build.BlockDelay, h.Height-baseTs.Height(), diff)
|
return xerrors.Errorf("block was generated too soon (h.ts:%d < base.mints:%d + BLOCK_DELAY:%d * deltaH:%d; diff %d)", h.Timestamp, baseTs.MinTimestamp(), build.BlockDelaySecs, h.Height-baseTs.Height(), diff)
|
||||||
}
|
}
|
||||||
|
|
||||||
msgsCheck := async.Err(func() error {
|
msgsCheck := async.Err(func() error {
|
||||||
@@ -639,7 +740,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
|
|||||||
return xerrors.Errorf("could not draw randomness: %w", err)
|
return xerrors.Errorf("could not draw randomness: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := gen.VerifyVRF(ctx, waddr, vrfBase, h.ElectionProof.VRFProof); err != nil {
|
if err := VerifyElectionPoStVRF(ctx, waddr, vrfBase, h.ElectionProof.VRFProof); err != nil {
|
||||||
return xerrors.Errorf("validating block election proof failed: %w", err)
|
return xerrors.Errorf("validating block election proof failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -665,7 +766,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
|
|||||||
})
|
})
|
||||||
|
|
||||||
blockSigCheck := async.Err(func() error {
|
blockSigCheck := async.Err(func() error {
|
||||||
if err := sigs.CheckBlockSignature(h, ctx, waddr); err != nil {
|
if err := sigs.CheckBlockSignature(ctx, h, waddr); err != nil {
|
||||||
return xerrors.Errorf("check block signature failed: %w", err)
|
return xerrors.Errorf("check block signature failed: %w", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -700,7 +801,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
|
|||||||
return xerrors.Errorf("failed to compute vrf base for ticket: %w", err)
|
return xerrors.Errorf("failed to compute vrf base for ticket: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = gen.VerifyVRF(ctx, waddr, vrfBase, h.Ticket.VRFProof)
|
err = VerifyElectionPoStVRF(ctx, waddr, vrfBase, h.Ticket.VRFProof)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("validating block tickets failed: %w", err)
|
return xerrors.Errorf("validating block tickets failed: %w", err)
|
||||||
}
|
}
|
||||||
@@ -748,7 +849,11 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return merr
|
if err := syncer.store.MarkBlockAsValidated(ctx, b.Cid()); err != nil {
|
||||||
|
return xerrors.Errorf("caching block validation %s: %w", b.Cid(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (syncer *Syncer) VerifyWinningPoStProof(ctx context.Context, h *types.BlockHeader, prevBeacon types.BeaconEntry, lbst cid.Cid, waddr address.Address) error {
|
func (syncer *Syncer) VerifyWinningPoStProof(ctx context.Context, h *types.BlockHeader, prevBeacon types.BeaconEntry, lbst cid.Cid, waddr address.Address) error {
|
||||||
@@ -846,7 +951,7 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock
|
|||||||
|
|
||||||
// Phase 1: syntactic validation, as defined in the spec
|
// Phase 1: syntactic validation, as defined in the spec
|
||||||
minGas := vm.PricelistByEpoch(baseTs.Height()).OnChainMessage(msg.ChainLength())
|
minGas := vm.PricelistByEpoch(baseTs.Height()).OnChainMessage(msg.ChainLength())
|
||||||
if err := m.ValidForBlockInclusion(minGas); err != nil {
|
if err := m.ValidForBlockInclusion(minGas.Total()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -938,23 +1043,14 @@ func (syncer *Syncer) verifyBlsAggregate(ctx context.Context, sig *crypto.Signat
|
|||||||
trace.Int64Attribute("msgCount", int64(len(msgs))),
|
trace.Int64Attribute("msgCount", int64(len(msgs))),
|
||||||
)
|
)
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
bmsgs := make([]bls.Message, len(msgs))
|
||||||
|
for i, m := range msgs {
|
||||||
digests := make([]bls.Digest, len(msgs))
|
bmsgs[i] = m.Bytes()
|
||||||
for i := 0; i < 10; i++ {
|
|
||||||
wg.Add(1)
|
|
||||||
go func(w int) {
|
|
||||||
defer wg.Done()
|
|
||||||
for j := 0; (j*10)+w < len(msgs); j++ {
|
|
||||||
digests[j*10+w] = bls.Hash(bls.Message(msgs[j*10+w].Bytes()))
|
|
||||||
}
|
|
||||||
}(i)
|
|
||||||
}
|
}
|
||||||
wg.Wait()
|
|
||||||
|
|
||||||
var bsig bls.Signature
|
var bsig bls.Signature
|
||||||
copy(bsig[:], sig.Data)
|
copy(bsig[:], sig.Data)
|
||||||
if !bls.Verify(&bsig, digests, pubks) {
|
if !bls.HashVerify(&bsig, bmsgs, pubks) {
|
||||||
return xerrors.New("bls aggregate signature failed to verify")
|
return xerrors.New("bls aggregate signature failed to verify")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -971,6 +1067,39 @@ func extractSyncState(ctx context.Context) *SyncerState {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// collectHeaders collects the headers from the blocks between any two tipsets.
|
||||||
|
//
|
||||||
|
// `from` is the heaviest/projected/target tipset we have learned about, and
|
||||||
|
// `to` is usually an anchor tipset we already have in our view of the chain
|
||||||
|
// (which could be the genesis).
|
||||||
|
//
|
||||||
|
// collectHeaders checks if portions of the chain are in our ChainStore; falling
|
||||||
|
// down to the network to retrieve the missing parts. If during the process, any
|
||||||
|
// portion we receive is in our denylist (bad list), we short-circuit.
|
||||||
|
//
|
||||||
|
// {hint/naming}: `from` and `to` is in inverse order. `from` is the highest,
|
||||||
|
// and `to` is the lowest. This method traverses the chain backwards.
|
||||||
|
//
|
||||||
|
// {hint/usage}: This is used by collectChain, which is in turn called from the
|
||||||
|
// main Sync method (Syncer#Sync), so it's a pretty central method.
|
||||||
|
//
|
||||||
|
// {hint/logic}: The logic of this method is as follows:
|
||||||
|
//
|
||||||
|
// 1. Check that the from tipset is not linked to a parent block known to be
|
||||||
|
// bad.
|
||||||
|
// 2. Check the consistency of beacon entries in the from tipset. We check
|
||||||
|
// total equality of the BeaconEntries in each block.
|
||||||
|
// 3. Travers the chain backwards, for each tipset:
|
||||||
|
// 3a. Load it from the chainstore; if found, it move on to its parent.
|
||||||
|
// 3b. Query our peers via BlockSync in batches, requesting up to a
|
||||||
|
// maximum of 500 tipsets every time.
|
||||||
|
//
|
||||||
|
// Once we've concluded, if we find a mismatching tipset at the height where the
|
||||||
|
// anchor tipset should be, we are facing a fork, and we invoke Syncer#syncFork
|
||||||
|
// to resolve it. Refer to the godocs there.
|
||||||
|
//
|
||||||
|
// All throughout the process, we keep checking if the received blocks are in
|
||||||
|
// the deny list, and short-circuit the process if so.
|
||||||
func (syncer *Syncer) collectHeaders(ctx context.Context, from *types.TipSet, to *types.TipSet) ([]*types.TipSet, error) {
|
func (syncer *Syncer) collectHeaders(ctx context.Context, from *types.TipSet, to *types.TipSet) ([]*types.TipSet, error) {
|
||||||
ctx, span := trace.StartSpan(ctx, "collectHeaders")
|
ctx, span := trace.StartSpan(ctx, "collectHeaders")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
@@ -987,6 +1116,8 @@ func (syncer *Syncer) collectHeaders(ctx context.Context, from *types.TipSet, to
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the parents of the from block are in the denylist.
|
||||||
|
// i.e. if a fork of the chain has been requested that we know to be bad.
|
||||||
for _, pcid := range from.Parents().Cids() {
|
for _, pcid := range from.Parents().Cids() {
|
||||||
if reason, ok := syncer.bad.Has(pcid); ok {
|
if reason, ok := syncer.bad.Has(pcid); ok {
|
||||||
markBad("linked to %s", pcid)
|
markBad("linked to %s", pcid)
|
||||||
@@ -1057,8 +1188,8 @@ loop:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NB: GetBlocks validates that the blocks are in-fact the ones we
|
// NB: GetBlocks validates that the blocks are in-fact the ones we
|
||||||
// requested, and that they are correctly linked to eachother. It does
|
// requested, and that they are correctly linked to one another. It does
|
||||||
// not validate any state transitions
|
// not validate any state transitions.
|
||||||
window := 500
|
window := 500
|
||||||
if gap := int(blockSet[len(blockSet)-1].Height() - untilHeight); gap < window {
|
if gap := int(blockSet[len(blockSet)-1].Height() - untilHeight); gap < window {
|
||||||
window = gap
|
window = gap
|
||||||
@@ -1099,7 +1230,6 @@ loop:
|
|||||||
at = blks[len(blks)-1].Parents()
|
at = blks[len(blks)-1].Parents()
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have now ascertained that this is *not* a 'fast forward'
|
|
||||||
if !types.CidArrsEqual(blockSet[len(blockSet)-1].Parents().Cids(), to.Cids()) {
|
if !types.CidArrsEqual(blockSet[len(blockSet)-1].Parents().Cids(), to.Cids()) {
|
||||||
last := blockSet[len(blockSet)-1]
|
last := blockSet[len(blockSet)-1]
|
||||||
if last.Parents() == to.Parents() {
|
if last.Parents() == to.Parents() {
|
||||||
@@ -1107,6 +1237,8 @@ loop:
|
|||||||
return blockSet, nil
|
return blockSet, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We have now ascertained that this is *not* a 'fast forward'
|
||||||
|
|
||||||
log.Warnf("(fork detected) synced header chain (%s - %d) does not link to our best block (%s - %d)", from.Cids(), from.Height(), to.Cids(), to.Height())
|
log.Warnf("(fork detected) synced header chain (%s - %d) does not link to our best block (%s - %d)", from.Cids(), from.Height(), to.Cids(), to.Height())
|
||||||
fork, err := syncer.syncFork(ctx, last, to)
|
fork, err := syncer.syncFork(ctx, last, to)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1128,6 +1260,12 @@ loop:
|
|||||||
|
|
||||||
var ErrForkTooLong = fmt.Errorf("fork longer than threshold")
|
var ErrForkTooLong = fmt.Errorf("fork longer than threshold")
|
||||||
|
|
||||||
|
// syncFork tries to obtain the chain fragment that links a fork into a common
|
||||||
|
// ancestor in our view of the chain.
|
||||||
|
//
|
||||||
|
// If the fork is too long (build.ForkLengthThreshold), we add the entire subchain to the
|
||||||
|
// denylist. Else, we find the common ancestor, and add the missing chain
|
||||||
|
// fragment until the fork point to the returned []TipSet.
|
||||||
func (syncer *Syncer) syncFork(ctx context.Context, from *types.TipSet, to *types.TipSet) ([]*types.TipSet, error) {
|
func (syncer *Syncer) syncFork(ctx context.Context, from *types.TipSet, to *types.TipSet) ([]*types.TipSet, error) {
|
||||||
tips, err := syncer.Bsync.GetBlocks(ctx, from.Parents(), int(build.ForkLengthThreshold))
|
tips, err := syncer.Bsync.GetBlocks(ctx, from.Parents(), int(build.ForkLengthThreshold))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1279,6 +1417,25 @@ func persistMessages(bs bstore.Blockstore, bst *blocksync.BSTipSet) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// collectChain tries to advance our view of the chain to the purported head.
|
||||||
|
//
|
||||||
|
// It goes through various stages:
|
||||||
|
//
|
||||||
|
// 1. StageHeaders: we proceed in the sync process by requesting block headers
|
||||||
|
// from our peers, moving back from their heads, until we reach a tipset
|
||||||
|
// that we have in common (such a common tipset must exist, thought it may
|
||||||
|
// simply be the genesis block).
|
||||||
|
//
|
||||||
|
// If the common tipset is our head, we treat the sync as a "fast-forward",
|
||||||
|
// else we must drop part of our chain to connect to the peer's head
|
||||||
|
// (referred to as "forking").
|
||||||
|
//
|
||||||
|
// 2. StagePersistHeaders: now that we've collected the missing headers,
|
||||||
|
// augmented by those on the other side of a fork, we persist them to the
|
||||||
|
// BlockStore.
|
||||||
|
//
|
||||||
|
// 3. StageMessages: having acquired the headers and found a common tipset,
|
||||||
|
// we then move forward, requesting the full blocks, including the messages.
|
||||||
func (syncer *Syncer) collectChain(ctx context.Context, ts *types.TipSet) error {
|
func (syncer *Syncer) collectChain(ctx context.Context, ts *types.TipSet) error {
|
||||||
ctx, span := trace.StartSpan(ctx, "collectChain")
|
ctx, span := trace.StartSpan(ctx, "collectChain")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
@@ -1325,12 +1482,11 @@ func (syncer *Syncer) collectChain(ctx context.Context, ts *types.TipSet) error
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func VerifyElectionPoStVRF(ctx context.Context, evrf []byte, rand []byte, worker address.Address) error {
|
func VerifyElectionPoStVRF(ctx context.Context, worker address.Address, rand []byte, evrf []byte) error {
|
||||||
if err := gen.VerifyVRF(ctx, worker, rand, evrf); err != nil {
|
if build.InsecurePoStValidation {
|
||||||
return xerrors.Errorf("failed to verify post_randomness vrf: %w", err)
|
return nil
|
||||||
}
|
}
|
||||||
|
return gen.VerifyVRF(ctx, worker, rand, evrf)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (syncer *Syncer) State() []SyncerState {
|
func (syncer *Syncer) State() []SyncerState {
|
||||||
@@ -1341,6 +1497,7 @@ func (syncer *Syncer) State() []SyncerState {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarkBad manually adds a block to the "bad blocks" cache.
|
||||||
func (syncer *Syncer) MarkBad(blk cid.Cid) {
|
func (syncer *Syncer) MarkBad(blk cid.Cid) {
|
||||||
syncer.bad.Add(blk, "manually marked bad")
|
syncer.bad.Add(blk, "manually marked bad")
|
||||||
}
|
}
|
||||||
@@ -1348,7 +1505,7 @@ func (syncer *Syncer) MarkBad(blk cid.Cid) {
|
|||||||
func (syncer *Syncer) CheckBadBlockCache(blk cid.Cid) (string, bool) {
|
func (syncer *Syncer) CheckBadBlockCache(blk cid.Cid) (string, bool) {
|
||||||
return syncer.bad.Has(blk)
|
return syncer.bad.Has(blk)
|
||||||
}
|
}
|
||||||
func (syncer *Syncer) getLatestBeaconEntry(ctx context.Context, ts *types.TipSet) (*types.BeaconEntry, error) {
|
func (syncer *Syncer) getLatestBeaconEntry(_ context.Context, ts *types.TipSet) (*types.BeaconEntry, error) {
|
||||||
cur := ts
|
cur := ts
|
||||||
for i := 0; i < 20; i++ {
|
for i := 0; i < 20; i++ {
|
||||||
cbe := cur.Blocks()[0].BeaconEntries
|
cbe := cur.Blocks()[0].BeaconEntries
|
||||||
@@ -1369,3 +1526,13 @@ func (syncer *Syncer) getLatestBeaconEntry(ctx context.Context, ts *types.TipSet
|
|||||||
|
|
||||||
return nil, xerrors.Errorf("found NO beacon entries in the 20 blocks prior to given tipset")
|
return nil, xerrors.Errorf("found NO beacon entries in the 20 blocks prior to given tipset")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (syncer *Syncer) IsEpochBeyondCurrMax(epoch abi.ChainEpoch) bool {
|
||||||
|
g, err := syncer.store.GetGenesis()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
now := uint64(time.Now().Unix())
|
||||||
|
return epoch > (abi.ChainEpoch((now-g.Timestamp)/build.BlockDelaySecs) + MaxHeightDrift)
|
||||||
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ type SyncManager struct {
|
|||||||
|
|
||||||
syncStates []*SyncerState
|
syncStates []*SyncerState
|
||||||
|
|
||||||
|
// Normally this handler is set to `(*Syncer).Sync()`.
|
||||||
doSync func(context.Context, *types.TipSet) error
|
doSync func(context.Context, *types.TipSet) error
|
||||||
|
|
||||||
stop chan struct{}
|
stop chan struct{}
|
||||||
@@ -280,7 +281,7 @@ func (sm *SyncManager) syncScheduler() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sm *SyncManager) scheduleIncoming(ts *types.TipSet) {
|
func (sm *SyncManager) scheduleIncoming(ts *types.TipSet) {
|
||||||
log.Info("scheduling incoming tipset sync: ", ts.Cids())
|
log.Debug("scheduling incoming tipset sync: ", ts.Cids())
|
||||||
if sm.getBootstrapState() == BSStateSelected {
|
if sm.getBootstrapState() == BSStateSelected {
|
||||||
sm.setBootstrapState(BSStateScheduled)
|
sm.setBootstrapState(BSStateScheduled)
|
||||||
sm.syncTargets <- ts
|
sm.syncTargets <- ts
|
||||||
|
|||||||
+3
-3
@@ -34,8 +34,8 @@ import (
|
|||||||
func init() {
|
func init() {
|
||||||
build.InsecurePoStValidation = true
|
build.InsecurePoStValidation = true
|
||||||
os.Setenv("TRUST_PARAMS", "1")
|
os.Setenv("TRUST_PARAMS", "1")
|
||||||
miner.SupportedProofTypes = map[abi.RegisteredProof]struct{}{
|
miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
|
||||||
abi.RegisteredProof_StackedDRG2KiBSeal: {},
|
abi.RegisteredSealProof_StackedDrg2KiBV1: {},
|
||||||
}
|
}
|
||||||
power.ConsensusMinerMinPower = big.NewInt(2048)
|
power.ConsensusMinerMinPower = big.NewInt(2048)
|
||||||
verifreg.MinVerifiedDealSize = big.NewInt(256)
|
verifreg.MinVerifiedDealSize = big.NewInt(256)
|
||||||
@@ -408,7 +408,7 @@ func TestSyncBadTimestamp(t *testing.T) {
|
|||||||
|
|
||||||
base := tu.g.CurTipset
|
base := tu.g.CurTipset
|
||||||
tu.g.Timestamper = func(pts *types.TipSet, tl abi.ChainEpoch) uint64 {
|
tu.g.Timestamper = func(pts *types.TipSet, tl abi.ChainEpoch) uint64 {
|
||||||
return pts.MinTimestamp() + (build.BlockDelay / 2)
|
return pts.MinTimestamp() + (build.BlockDelaySecs / 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("BASE: ", base.Cids())
|
fmt.Println("BASE: ", base.Cids())
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ func SizeStr(bi BigInt) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
f, _ := r.Float64()
|
f, _ := r.Float64()
|
||||||
return fmt.Sprintf("%.3g %s", f, byteSizeUnits[i])
|
return fmt.Sprintf("%.4g %s", f, byteSizeUnits[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
var deciUnits = []string{"", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"}
|
var deciUnits = []string{"", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"}
|
||||||
|
|||||||
@@ -3,7 +3,12 @@ package types
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"math/rand"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/docker/go-units"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
@@ -60,8 +65,10 @@ func TestSizeStr(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{0, "0 B"},
|
{0, "0 B"},
|
||||||
{1, "1 B"},
|
{1, "1 B"},
|
||||||
|
{1016, "1016 B"},
|
||||||
{1024, "1 KiB"},
|
{1024, "1 KiB"},
|
||||||
{2000, "1.95 KiB"},
|
{1000 * 1024, "1000 KiB"},
|
||||||
|
{2000, "1.953 KiB"},
|
||||||
{5 << 20, "5 MiB"},
|
{5 << 20, "5 MiB"},
|
||||||
{11 << 60, "11 EiB"},
|
{11 << 60, "11 EiB"},
|
||||||
}
|
}
|
||||||
@@ -71,6 +78,22 @@ func TestSizeStr(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSizeStrUnitsSymmetry(t *testing.T) {
|
||||||
|
s := rand.NewSource(time.Now().UnixNano())
|
||||||
|
r := rand.New(s)
|
||||||
|
|
||||||
|
for i := 0; i < 1000000; i++ {
|
||||||
|
n := r.Uint64()
|
||||||
|
l := strings.ReplaceAll(units.BytesSize(float64(n)), " ", "")
|
||||||
|
r := strings.ReplaceAll(SizeStr(NewInt(n)), " ", "")
|
||||||
|
|
||||||
|
assert.NotContains(t, l, "e+")
|
||||||
|
assert.NotContains(t, r, "e+")
|
||||||
|
|
||||||
|
assert.Equal(t, l, r, "wrong formatting for %d", n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestSizeStrBig(t *testing.T) {
|
func TestSizeStrBig(t *testing.T) {
|
||||||
ZiB := big.NewInt(50000)
|
ZiB := big.NewInt(50000)
|
||||||
ZiB = ZiB.Lsh(ZiB, 70)
|
ZiB = ZiB.Lsh(ZiB, 70)
|
||||||
|
|||||||
@@ -74,8 +74,8 @@ type BlockHeader struct {
|
|||||||
validated bool // true if the signature has been validated
|
validated bool // true if the signature has been validated
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BlockHeader) ToStorageBlock() (block.Block, error) {
|
func (blk *BlockHeader) ToStorageBlock() (block.Block, error) {
|
||||||
data, err := b.Serialize()
|
data, err := blk.Serialize()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -89,8 +89,8 @@ func (b *BlockHeader) ToStorageBlock() (block.Block, error) {
|
|||||||
return block.NewBlockWithCid(data, c)
|
return block.NewBlockWithCid(data, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BlockHeader) Cid() cid.Cid {
|
func (blk *BlockHeader) Cid() cid.Cid {
|
||||||
sb, err := b.ToStorageBlock()
|
sb, err := blk.ToStorageBlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err) // Not sure i'm entirely comfortable with this one, needs to be checked
|
panic(err) // Not sure i'm entirely comfortable with this one, needs to be checked
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -79,7 +80,7 @@ func TestInteropBH(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
posts := []abi.PoStProof{
|
posts := []abi.PoStProof{
|
||||||
{abi.RegisteredProof_StackedDRG2KiBWinningPoSt, []byte{0x07}},
|
{abi.RegisteredPoStProof_StackedDrgWinning2KiBV1, []byte{0x07}},
|
||||||
}
|
}
|
||||||
|
|
||||||
bh := &BlockHeader{
|
bh := &BlockHeader{
|
||||||
@@ -116,10 +117,8 @@ func TestInteropBH(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// acquired from go-filecoin
|
// acquired from go-filecoin
|
||||||
gfc := "8f5501d04cb15021bf6bd003073d79e2238d4e61f1ad22814301020381420a0b818205410c818209410781d82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619cc430003e802d82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619ccd82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619ccd82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619cc410001f603"
|
gfc := "8f5501d04cb15021bf6bd003073d79e2238d4e61f1ad22814301020381420a0b818205410c818200410781d82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619cc430003e802d82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619ccd82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619ccd82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619cc410001f603"
|
||||||
if gfc != hex.EncodeToString(bhsb) {
|
require.Equal(t, gfc, hex.EncodeToString(bhsb))
|
||||||
t.Fatal("not equal!")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkBlockHeaderMarshal(b *testing.B) {
|
func BenchmarkBlockHeaderMarshal(b *testing.B) {
|
||||||
|
|||||||
@@ -1,9 +1,103 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
type ExecutionResult struct {
|
import (
|
||||||
Msg *Message
|
"encoding/json"
|
||||||
MsgRct *MessageReceipt
|
"fmt"
|
||||||
Error string
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
Subcalls []*ExecutionResult
|
type ExecutionTrace struct {
|
||||||
|
Msg *Message
|
||||||
|
MsgRct *MessageReceipt
|
||||||
|
Error string
|
||||||
|
Duration time.Duration
|
||||||
|
GasCharges []*GasTrace
|
||||||
|
|
||||||
|
Subcalls []ExecutionTrace
|
||||||
|
}
|
||||||
|
|
||||||
|
type GasTrace struct {
|
||||||
|
Name string
|
||||||
|
|
||||||
|
Location []Loc `json:"loc"`
|
||||||
|
TotalGas int64 `json:"tg"`
|
||||||
|
ComputeGas int64 `json:"cg"`
|
||||||
|
StorageGas int64 `json:"sg"`
|
||||||
|
TotalVirtualGas int64 `json:"vtg"`
|
||||||
|
VirtualComputeGas int64 `json:"vcg"`
|
||||||
|
VirtualStorageGas int64 `json:"vsg"`
|
||||||
|
|
||||||
|
TimeTaken time.Duration `json:"tt"`
|
||||||
|
Extra interface{} `json:"ex,omitempty"`
|
||||||
|
|
||||||
|
Callers []uintptr `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Loc struct {
|
||||||
|
File string
|
||||||
|
Line int
|
||||||
|
Function string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l Loc) Show() bool {
|
||||||
|
ignorePrefix := []string{
|
||||||
|
"reflect.",
|
||||||
|
"github.com/filecoin-project/lotus/chain/vm.(*Invoker).transform",
|
||||||
|
"github.com/filecoin-project/go-amt-ipld/",
|
||||||
|
}
|
||||||
|
for _, pre := range ignorePrefix {
|
||||||
|
if strings.HasPrefix(l.Function, pre) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
func (l Loc) String() string {
|
||||||
|
file := strings.Split(l.File, "/")
|
||||||
|
|
||||||
|
fn := strings.Split(l.Function, "/")
|
||||||
|
var fnpkg string
|
||||||
|
if len(fn) > 2 {
|
||||||
|
fnpkg = strings.Join(fn[len(fn)-2:], "/")
|
||||||
|
} else {
|
||||||
|
fnpkg = l.Function
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("%s@%s:%d", fnpkg, file[len(file)-1], l.Line)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l Loc) Important() bool {
|
||||||
|
if strings.HasPrefix(l.Function, "github.com/filecoin-project/specs-actors/actors/builtin") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gt *GasTrace) MarshalJSON() ([]byte, error) {
|
||||||
|
type GasTraceCopy GasTrace
|
||||||
|
if len(gt.Location) == 0 {
|
||||||
|
if len(gt.Callers) != 0 {
|
||||||
|
frames := runtime.CallersFrames(gt.Callers)
|
||||||
|
for {
|
||||||
|
frame, more := frames.Next()
|
||||||
|
if frame.Function == "github.com/filecoin-project/lotus/chain/vm.(*VM).ApplyMessage" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
l := Loc{
|
||||||
|
File: frame.File,
|
||||||
|
Line: frame.Line,
|
||||||
|
Function: frame.Function,
|
||||||
|
}
|
||||||
|
gt.Location = append(gt.Location, l)
|
||||||
|
if !more {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cpy := (*GasTraceCopy)(gt)
|
||||||
|
return json.Marshal(cpy)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -11,7 +11,7 @@ import (
|
|||||||
type FIL BigInt
|
type FIL BigInt
|
||||||
|
|
||||||
func (f FIL) String() string {
|
func (f FIL) String() string {
|
||||||
r := new(big.Rat).SetFrac(f.Int, big.NewInt(build.FilecoinPrecision))
|
r := new(big.Rat).SetFrac(f.Int, big.NewInt(int64(build.FilecoinPrecision)))
|
||||||
if r.Sign() == 0 {
|
if r.Sign() == 0 {
|
||||||
return "0"
|
return "0"
|
||||||
}
|
}
|
||||||
@@ -33,7 +33,7 @@ func ParseFIL(s string) (FIL, error) {
|
|||||||
return FIL{}, fmt.Errorf("failed to parse %q as a decimal number", s)
|
return FIL{}, fmt.Errorf("failed to parse %q as a decimal number", s)
|
||||||
}
|
}
|
||||||
|
|
||||||
r = r.Mul(r, big.NewRat(build.FilecoinPrecision, 1))
|
r = r.Mul(r, big.NewRat(int64(build.FilecoinPrecision), 1))
|
||||||
if !r.IsInt() {
|
if !r.IsInt() {
|
||||||
return FIL{}, fmt.Errorf("invalid FIL value: %q", s)
|
return FIL{}, fmt.Errorf("invalid FIL value: %q", s)
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-10
@@ -21,6 +21,7 @@ type ChainMsg interface {
|
|||||||
Cid() cid.Cid
|
Cid() cid.Cid
|
||||||
VMMessage() *Message
|
VMMessage() *Message
|
||||||
ToStorageBlock() (block.Block, error)
|
ToStorageBlock() (block.Block, error)
|
||||||
|
// FIXME: This is the *message* length, this name is misleading.
|
||||||
ChainLength() int
|
ChainLength() int
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,20 +42,16 @@ type Message struct {
|
|||||||
Params []byte
|
Params []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Message) BlockMiner() address.Address {
|
func (m *Message) Caller() address.Address {
|
||||||
panic("implement me")
|
return m.From
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Message) Caller() address.Address {
|
func (m *Message) Receiver() address.Address {
|
||||||
return t.From
|
return m.To
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Message) Receiver() address.Address {
|
func (m *Message) ValueReceived() abi.TokenAmount {
|
||||||
return t.To
|
return m.Value
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Message) ValueReceived() abi.TokenAmount {
|
|
||||||
return t.Value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecodeMessage(b []byte) (*Message, error) {
|
func DecodeMessage(b []byte) (*Message, error) {
|
||||||
|
|||||||
@@ -49,6 +49,11 @@ func MkBlock(parents *types.TipSet, weightInc uint64, ticketNonce uint64) *types
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pstateRoot := c
|
||||||
|
if parents != nil {
|
||||||
|
pstateRoot = parents.Blocks()[0].ParentStateRoot
|
||||||
|
}
|
||||||
|
|
||||||
var pcids []cid.Cid
|
var pcids []cid.Cid
|
||||||
var height abi.ChainEpoch
|
var height abi.ChainEpoch
|
||||||
weight := types.NewInt(weightInc)
|
weight := types.NewInt(weightInc)
|
||||||
@@ -72,7 +77,7 @@ func MkBlock(parents *types.TipSet, weightInc uint64, ticketNonce uint64) *types
|
|||||||
ParentWeight: weight,
|
ParentWeight: weight,
|
||||||
Messages: c,
|
Messages: c,
|
||||||
Height: height,
|
Height: height,
|
||||||
ParentStateRoot: c,
|
ParentStateRoot: pstateRoot,
|
||||||
BlockSig: &crypto.Signature{Type: crypto.SigTypeBLS, Data: []byte("boo! im a signature")},
|
BlockSig: &crypto.Signature{Type: crypto.SigTypeBLS, Data: []byte("boo! im a signature")},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,12 +9,12 @@ import (
|
|||||||
"github.com/multiformats/go-multihash"
|
"github.com/multiformats/go-multihash"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (m *SignedMessage) ToStorageBlock() (block.Block, error) {
|
func (sm *SignedMessage) ToStorageBlock() (block.Block, error) {
|
||||||
if m.Signature.Type == crypto.SigTypeBLS {
|
if sm.Signature.Type == crypto.SigTypeBLS {
|
||||||
return m.Message.ToStorageBlock()
|
return sm.Message.ToStorageBlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := m.Serialize()
|
data, err := sm.Serialize()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -28,12 +28,12 @@ func (m *SignedMessage) ToStorageBlock() (block.Block, error) {
|
|||||||
return block.NewBlockWithCid(data, c)
|
return block.NewBlockWithCid(data, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *SignedMessage) Cid() cid.Cid {
|
func (sm *SignedMessage) Cid() cid.Cid {
|
||||||
if m.Signature.Type == crypto.SigTypeBLS {
|
if sm.Signature.Type == crypto.SigTypeBLS {
|
||||||
return m.Message.Cid()
|
return sm.Message.Cid()
|
||||||
}
|
}
|
||||||
|
|
||||||
sb, err := m.ToStorageBlock()
|
sb, err := sm.ToStorageBlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,8 +23,6 @@ type TipSet struct {
|
|||||||
height abi.ChainEpoch
|
height abi.ChainEpoch
|
||||||
}
|
}
|
||||||
|
|
||||||
// why didnt i just export the fields? Because the struct has methods with the
|
|
||||||
// same names already
|
|
||||||
type ExpTipSet struct {
|
type ExpTipSet struct {
|
||||||
Cids []cid.Cid
|
Cids []cid.Cid
|
||||||
Blocks []*BlockHeader
|
Blocks []*BlockHeader
|
||||||
@@ -32,6 +30,8 @@ type ExpTipSet struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ts *TipSet) MarshalJSON() ([]byte, error) {
|
func (ts *TipSet) MarshalJSON() ([]byte, error) {
|
||||||
|
// why didnt i just export the fields? Because the struct has methods with the
|
||||||
|
// same names already
|
||||||
return json.Marshal(ExpTipSet{
|
return json.Marshal(ExpTipSet{
|
||||||
Cids: ts.cids,
|
Cids: ts.cids,
|
||||||
Blocks: ts.blks,
|
Blocks: ts.blks,
|
||||||
|
|||||||
@@ -61,9 +61,9 @@ func TestTipSetKey(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("JSON", func(t *testing.T) {
|
t.Run("JSON", func(t *testing.T) {
|
||||||
k0 := NewTipSetKey()
|
k0 := NewTipSetKey()
|
||||||
verifyJson(t, "[]", k0)
|
verifyJSON(t, "[]", k0)
|
||||||
k3 := NewTipSetKey(c1, c2, c3)
|
k3 := NewTipSetKey(c1, c2, c3)
|
||||||
verifyJson(t, `[`+
|
verifyJSON(t, `[`+
|
||||||
`{"/":"bafy2bzacecesrkxghscnq7vatble2hqdvwat6ed23vdu4vvo3uuggsoaya7ki"},`+
|
`{"/":"bafy2bzacecesrkxghscnq7vatble2hqdvwat6ed23vdu4vvo3uuggsoaya7ki"},`+
|
||||||
`{"/":"bafy2bzacebxfyh2fzoxrt6kcgc5dkaodpcstgwxxdizrww225vrhsizsfcg4g"},`+
|
`{"/":"bafy2bzacebxfyh2fzoxrt6kcgc5dkaodpcstgwxxdizrww225vrhsizsfcg4g"},`+
|
||||||
`{"/":"bafy2bzacedwviarjtjraqakob5pslltmuo5n3xev3nt5zylezofkbbv5jclyu"}`+
|
`{"/":"bafy2bzacedwviarjtjraqakob5pslltmuo5n3xev3nt5zylezofkbbv5jclyu"}`+
|
||||||
@@ -71,7 +71,7 @@ func TestTipSetKey(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyJson(t *testing.T, expected string, k TipSetKey) {
|
func verifyJSON(t *testing.T, expected string, k TipSetKey) {
|
||||||
bytes, err := json.Marshal(k)
|
bytes, err := json.Marshal(k)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, expected, string(bytes))
|
assert.Equal(t, expected, string(bytes))
|
||||||
|
|||||||
+77
-16
@@ -12,34 +12,74 @@ import (
|
|||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
GasStorageMulti = 1
|
||||||
|
GasComputeMulti = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
type GasCharge struct {
|
||||||
|
Name string
|
||||||
|
Extra interface{}
|
||||||
|
|
||||||
|
ComputeGas int64
|
||||||
|
StorageGas int64
|
||||||
|
|
||||||
|
VirtualCompute int64
|
||||||
|
VirtualStorage int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g GasCharge) Total() int64 {
|
||||||
|
return g.ComputeGas*GasComputeMulti + g.StorageGas*GasStorageMulti
|
||||||
|
}
|
||||||
|
func (g GasCharge) WithVirtual(compute, storage int64) GasCharge {
|
||||||
|
out := g
|
||||||
|
out.VirtualCompute = compute
|
||||||
|
out.VirtualStorage = storage
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g GasCharge) WithExtra(extra interface{}) GasCharge {
|
||||||
|
out := g
|
||||||
|
out.Extra = extra
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func newGasCharge(name string, computeGas int64, storageGas int64) GasCharge {
|
||||||
|
return GasCharge{
|
||||||
|
Name: name,
|
||||||
|
ComputeGas: computeGas,
|
||||||
|
StorageGas: storageGas,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Pricelist provides prices for operations in the VM.
|
// Pricelist provides prices for operations in the VM.
|
||||||
//
|
//
|
||||||
// Note: this interface should be APPEND ONLY since last chain checkpoint
|
// Note: this interface should be APPEND ONLY since last chain checkpoint
|
||||||
type Pricelist interface {
|
type Pricelist interface {
|
||||||
// OnChainMessage returns the gas used for storing a message of a given size in the chain.
|
// OnChainMessage returns the gas used for storing a message of a given size in the chain.
|
||||||
OnChainMessage(msgSize int) int64
|
OnChainMessage(msgSize int) GasCharge
|
||||||
// OnChainReturnValue returns the gas used for storing the response of a message in the chain.
|
// OnChainReturnValue returns the gas used for storing the response of a message in the chain.
|
||||||
OnChainReturnValue(dataSize int) int64
|
OnChainReturnValue(dataSize int) GasCharge
|
||||||
|
|
||||||
// OnMethodInvocation returns the gas used when invoking a method.
|
// OnMethodInvocation returns the gas used when invoking a method.
|
||||||
OnMethodInvocation(value abi.TokenAmount, methodNum abi.MethodNum) int64
|
OnMethodInvocation(value abi.TokenAmount, methodNum abi.MethodNum) GasCharge
|
||||||
|
|
||||||
// OnIpldGet returns the gas used for storing an object
|
// OnIpldGet returns the gas used for storing an object
|
||||||
OnIpldGet(dataSize int) int64
|
OnIpldGet(dataSize int) GasCharge
|
||||||
// OnIpldPut returns the gas used for storing an object
|
// OnIpldPut returns the gas used for storing an object
|
||||||
OnIpldPut(dataSize int) int64
|
OnIpldPut(dataSize int) GasCharge
|
||||||
|
|
||||||
// OnCreateActor returns the gas used for creating an actor
|
// OnCreateActor returns the gas used for creating an actor
|
||||||
OnCreateActor() int64
|
OnCreateActor() GasCharge
|
||||||
// OnDeleteActor returns the gas used for deleting an actor
|
// OnDeleteActor returns the gas used for deleting an actor
|
||||||
OnDeleteActor() int64
|
OnDeleteActor() GasCharge
|
||||||
|
|
||||||
OnVerifySignature(sigType crypto.SigType, planTextSize int) (int64, error)
|
OnVerifySignature(sigType crypto.SigType, planTextSize int) (GasCharge, error)
|
||||||
OnHashing(dataSize int) int64
|
OnHashing(dataSize int) GasCharge
|
||||||
OnComputeUnsealedSectorCid(proofType abi.RegisteredProof, pieces []abi.PieceInfo) int64
|
OnComputeUnsealedSectorCid(proofType abi.RegisteredSealProof, pieces []abi.PieceInfo) GasCharge
|
||||||
OnVerifySeal(info abi.SealVerifyInfo) int64
|
OnVerifySeal(info abi.SealVerifyInfo) GasCharge
|
||||||
OnVerifyPost(info abi.WindowPoStVerifyInfo) int64
|
OnVerifyPost(info abi.WindowPoStVerifyInfo) GasCharge
|
||||||
OnVerifyConsensusFault() int64
|
OnVerifyConsensusFault() GasCharge
|
||||||
}
|
}
|
||||||
|
|
||||||
var prices = map[abi.ChainEpoch]Pricelist{
|
var prices = map[abi.ChainEpoch]Pricelist{
|
||||||
@@ -93,7 +133,7 @@ func PricelistByEpoch(epoch abi.ChainEpoch) Pricelist {
|
|||||||
type pricedSyscalls struct {
|
type pricedSyscalls struct {
|
||||||
under vmr.Syscalls
|
under vmr.Syscalls
|
||||||
pl Pricelist
|
pl Pricelist
|
||||||
chargeGas func(int64)
|
chargeGas func(GasCharge)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verifies that a signature is valid for an address and plaintext.
|
// Verifies that a signature is valid for an address and plaintext.
|
||||||
@@ -103,30 +143,40 @@ func (ps pricedSyscalls) VerifySignature(signature crypto.Signature, signer addr
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ps.chargeGas(c)
|
ps.chargeGas(c)
|
||||||
|
defer ps.chargeGas(gasOnActorExec)
|
||||||
|
|
||||||
return ps.under.VerifySignature(signature, signer, plaintext)
|
return ps.under.VerifySignature(signature, signer, plaintext)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hashes input data using blake2b with 256 bit output.
|
// Hashes input data using blake2b with 256 bit output.
|
||||||
func (ps pricedSyscalls) HashBlake2b(data []byte) [32]byte {
|
func (ps pricedSyscalls) HashBlake2b(data []byte) [32]byte {
|
||||||
ps.chargeGas(ps.pl.OnHashing(len(data)))
|
ps.chargeGas(ps.pl.OnHashing(len(data)))
|
||||||
|
defer ps.chargeGas(gasOnActorExec)
|
||||||
|
|
||||||
return ps.under.HashBlake2b(data)
|
return ps.under.HashBlake2b(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Computes an unsealed sector CID (CommD) from its constituent piece CIDs (CommPs) and sizes.
|
// Computes an unsealed sector CID (CommD) from its constituent piece CIDs (CommPs) and sizes.
|
||||||
func (ps pricedSyscalls) ComputeUnsealedSectorCID(reg abi.RegisteredProof, pieces []abi.PieceInfo) (cid.Cid, error) {
|
func (ps pricedSyscalls) ComputeUnsealedSectorCID(reg abi.RegisteredSealProof, pieces []abi.PieceInfo) (cid.Cid, error) {
|
||||||
ps.chargeGas(ps.pl.OnComputeUnsealedSectorCid(reg, pieces))
|
ps.chargeGas(ps.pl.OnComputeUnsealedSectorCid(reg, pieces))
|
||||||
|
defer ps.chargeGas(gasOnActorExec)
|
||||||
|
|
||||||
return ps.under.ComputeUnsealedSectorCID(reg, pieces)
|
return ps.under.ComputeUnsealedSectorCID(reg, pieces)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verifies a sector seal proof.
|
// Verifies a sector seal proof.
|
||||||
func (ps pricedSyscalls) VerifySeal(vi abi.SealVerifyInfo) error {
|
func (ps pricedSyscalls) VerifySeal(vi abi.SealVerifyInfo) error {
|
||||||
ps.chargeGas(ps.pl.OnVerifySeal(vi))
|
ps.chargeGas(ps.pl.OnVerifySeal(vi))
|
||||||
|
defer ps.chargeGas(gasOnActorExec)
|
||||||
|
|
||||||
return ps.under.VerifySeal(vi)
|
return ps.under.VerifySeal(vi)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verifies a proof of spacetime.
|
// Verifies a proof of spacetime.
|
||||||
func (ps pricedSyscalls) VerifyPoSt(vi abi.WindowPoStVerifyInfo) error {
|
func (ps pricedSyscalls) VerifyPoSt(vi abi.WindowPoStVerifyInfo) error {
|
||||||
ps.chargeGas(ps.pl.OnVerifyPost(vi))
|
ps.chargeGas(ps.pl.OnVerifyPost(vi))
|
||||||
|
defer ps.chargeGas(gasOnActorExec)
|
||||||
|
|
||||||
return ps.under.VerifyPoSt(vi)
|
return ps.under.VerifyPoSt(vi)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,10 +192,21 @@ func (ps pricedSyscalls) VerifyPoSt(vi abi.WindowPoStVerifyInfo) error {
|
|||||||
// Returns nil and an error if the headers don't prove a fault.
|
// Returns nil and an error if the headers don't prove a fault.
|
||||||
func (ps pricedSyscalls) VerifyConsensusFault(h1 []byte, h2 []byte, extra []byte) (*runtime.ConsensusFault, error) {
|
func (ps pricedSyscalls) VerifyConsensusFault(h1 []byte, h2 []byte, extra []byte) (*runtime.ConsensusFault, error) {
|
||||||
ps.chargeGas(ps.pl.OnVerifyConsensusFault())
|
ps.chargeGas(ps.pl.OnVerifyConsensusFault())
|
||||||
|
defer ps.chargeGas(gasOnActorExec)
|
||||||
|
|
||||||
return ps.under.VerifyConsensusFault(h1, h2, extra)
|
return ps.under.VerifyConsensusFault(h1, h2, extra)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps pricedSyscalls) BatchVerifySeals(inp map[address.Address][]abi.SealVerifyInfo) (map[address.Address][]bool, error) {
|
func (ps pricedSyscalls) BatchVerifySeals(inp map[address.Address][]abi.SealVerifyInfo) (map[address.Address][]bool, error) {
|
||||||
ps.chargeGas(0) // TODO: this is only called by the cron actor. Should we even charge gas?
|
var gasChargeSum GasCharge
|
||||||
|
gasChargeSum.Name = "BatchVerifySeals"
|
||||||
|
count := int64(0)
|
||||||
|
for _, svis := range inp {
|
||||||
|
count += int64(len(svis))
|
||||||
|
}
|
||||||
|
gasChargeSum = gasChargeSum.WithExtra(count).WithVirtual(129778623*count+716683250, 0)
|
||||||
|
ps.chargeGas(gasChargeSum) // TODO: this is only called by the cron actor. Should we even charge gas?
|
||||||
|
defer ps.chargeGas(gasOnActorExec)
|
||||||
|
|
||||||
return ps.under.BatchVerifySeals(inp)
|
return ps.under.BatchVerifySeals(inp)
|
||||||
}
|
}
|
||||||
|
|||||||
+61
-27
@@ -2,7 +2,9 @@ package vm
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
"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"
|
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||||
)
|
)
|
||||||
@@ -84,80 +86,112 @@ type pricelistV0 struct {
|
|||||||
var _ Pricelist = (*pricelistV0)(nil)
|
var _ Pricelist = (*pricelistV0)(nil)
|
||||||
|
|
||||||
// OnChainMessage returns the gas used for storing a message of a given size in the chain.
|
// OnChainMessage returns the gas used for storing a message of a given size in the chain.
|
||||||
func (pl *pricelistV0) OnChainMessage(msgSize int) int64 {
|
func (pl *pricelistV0) OnChainMessage(msgSize int) GasCharge {
|
||||||
return pl.onChainMessageBase + pl.onChainMessagePerByte*int64(msgSize)
|
return newGasCharge("OnChainMessage", 0, pl.onChainMessageBase+pl.onChainMessagePerByte*int64(msgSize)).WithVirtual(77302, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnChainReturnValue returns the gas used for storing the response of a message in the chain.
|
// OnChainReturnValue returns the gas used for storing the response of a message in the chain.
|
||||||
func (pl *pricelistV0) OnChainReturnValue(dataSize int) int64 {
|
func (pl *pricelistV0) OnChainReturnValue(dataSize int) GasCharge {
|
||||||
return int64(dataSize) * pl.onChainReturnValuePerByte
|
return newGasCharge("OnChainReturnValue", 0, int64(dataSize)*pl.onChainReturnValuePerByte).WithVirtual(107294, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnMethodInvocation returns the gas used when invoking a method.
|
// OnMethodInvocation returns the gas used when invoking a method.
|
||||||
func (pl *pricelistV0) OnMethodInvocation(value abi.TokenAmount, methodNum abi.MethodNum) int64 {
|
func (pl *pricelistV0) OnMethodInvocation(value abi.TokenAmount, methodNum abi.MethodNum) GasCharge {
|
||||||
ret := pl.sendBase
|
ret := pl.sendBase
|
||||||
|
extra := ""
|
||||||
|
virtGas := int64(1072944)
|
||||||
|
|
||||||
if value != abi.NewTokenAmount(0) {
|
if value != abi.NewTokenAmount(0) {
|
||||||
|
// TODO: fix this, it is comparing pointers instead of values
|
||||||
|
// see vv
|
||||||
ret += pl.sendTransferFunds
|
ret += pl.sendTransferFunds
|
||||||
}
|
}
|
||||||
|
if big.Cmp(value, abi.NewTokenAmount(0)) != 0 {
|
||||||
|
virtGas += 497495
|
||||||
|
if methodNum == builtin.MethodSend {
|
||||||
|
// transfer only
|
||||||
|
virtGas += 973940
|
||||||
|
}
|
||||||
|
extra += "t"
|
||||||
|
}
|
||||||
if methodNum != builtin.MethodSend {
|
if methodNum != builtin.MethodSend {
|
||||||
ret += pl.sendInvokeMethod
|
ret += pl.sendInvokeMethod
|
||||||
|
extra += "i"
|
||||||
|
// running actors is cheaper becase we hand over to actors
|
||||||
|
virtGas += -295779
|
||||||
}
|
}
|
||||||
return ret
|
return newGasCharge("OnMethodInvocation", ret, 0).WithVirtual(virtGas, 0).WithExtra(extra)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnIpldGet returns the gas used for storing an object
|
// OnIpldGet returns the gas used for storing an object
|
||||||
func (pl *pricelistV0) OnIpldGet(dataSize int) int64 {
|
func (pl *pricelistV0) OnIpldGet(dataSize int) GasCharge {
|
||||||
return pl.ipldGetBase + int64(dataSize)*pl.ipldGetPerByte
|
return newGasCharge("OnIpldGet", pl.ipldGetBase+int64(dataSize)*pl.ipldGetPerByte, 0).
|
||||||
|
WithExtra(dataSize).WithVirtual(433685, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnIpldPut returns the gas used for storing an object
|
// OnIpldPut returns the gas used for storing an object
|
||||||
func (pl *pricelistV0) OnIpldPut(dataSize int) int64 {
|
func (pl *pricelistV0) OnIpldPut(dataSize int) GasCharge {
|
||||||
return pl.ipldPutBase + int64(dataSize)*pl.ipldPutPerByte
|
return newGasCharge("OnIpldPut", pl.ipldPutBase, int64(dataSize)*pl.ipldPutPerByte).
|
||||||
|
WithExtra(dataSize).WithVirtual(88970, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnCreateActor returns the gas used for creating an actor
|
// OnCreateActor returns the gas used for creating an actor
|
||||||
func (pl *pricelistV0) OnCreateActor() int64 {
|
func (pl *pricelistV0) OnCreateActor() GasCharge {
|
||||||
return pl.createActorBase + pl.createActorExtra
|
return newGasCharge("OnCreateActor", pl.createActorBase, pl.createActorExtra).WithVirtual(65636, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnDeleteActor returns the gas used for deleting an actor
|
// OnDeleteActor returns the gas used for deleting an actor
|
||||||
func (pl *pricelistV0) OnDeleteActor() int64 {
|
func (pl *pricelistV0) OnDeleteActor() GasCharge {
|
||||||
return pl.deleteActor
|
return newGasCharge("OnDeleteActor", 0, pl.deleteActor)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnVerifySignature
|
// OnVerifySignature
|
||||||
func (pl *pricelistV0) OnVerifySignature(sigType crypto.SigType, planTextSize int) (int64, error) {
|
|
||||||
|
func (pl *pricelistV0) OnVerifySignature(sigType crypto.SigType, planTextSize int) (GasCharge, error) {
|
||||||
costFn, ok := pl.verifySignature[sigType]
|
costFn, ok := pl.verifySignature[sigType]
|
||||||
if !ok {
|
if !ok {
|
||||||
return 0, fmt.Errorf("cost function for signature type %d not supported", sigType)
|
return GasCharge{}, fmt.Errorf("cost function for signature type %d not supported", sigType)
|
||||||
}
|
}
|
||||||
return costFn(int64(planTextSize)), nil
|
sigName, _ := sigType.Name()
|
||||||
|
virtGas := int64(0)
|
||||||
|
switch sigType {
|
||||||
|
case crypto.SigTypeBLS:
|
||||||
|
virtGas = 220138570
|
||||||
|
case crypto.SigTypeSecp256k1:
|
||||||
|
virtGas = 7053730
|
||||||
|
}
|
||||||
|
|
||||||
|
return newGasCharge("OnVerifySignature", costFn(int64(planTextSize)), 0).
|
||||||
|
WithExtra(map[string]interface{}{
|
||||||
|
"type": sigName,
|
||||||
|
"size": planTextSize,
|
||||||
|
}).WithVirtual(virtGas, 0), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnHashing
|
// OnHashing
|
||||||
func (pl *pricelistV0) OnHashing(dataSize int) int64 {
|
func (pl *pricelistV0) OnHashing(dataSize int) GasCharge {
|
||||||
return pl.hashingBase + int64(dataSize)*pl.hashingPerByte
|
return newGasCharge("OnHashing", pl.hashingBase+int64(dataSize)*pl.hashingPerByte, 0).WithExtra(dataSize).WithVirtual(77300, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnComputeUnsealedSectorCid
|
// OnComputeUnsealedSectorCid
|
||||||
func (pl *pricelistV0) OnComputeUnsealedSectorCid(proofType abi.RegisteredProof, pieces []abi.PieceInfo) int64 {
|
func (pl *pricelistV0) OnComputeUnsealedSectorCid(proofType abi.RegisteredSealProof, pieces []abi.PieceInfo) GasCharge {
|
||||||
// TODO: this needs more cost tunning, check with @lotus
|
// TODO: this needs more cost tunning, check with @lotus
|
||||||
return pl.computeUnsealedSectorCidBase
|
return newGasCharge("OnComputeUnsealedSectorCid", pl.computeUnsealedSectorCidBase, 0).WithVirtual(382370, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnVerifySeal
|
// OnVerifySeal
|
||||||
func (pl *pricelistV0) OnVerifySeal(info abi.SealVerifyInfo) int64 {
|
func (pl *pricelistV0) OnVerifySeal(info abi.SealVerifyInfo) GasCharge {
|
||||||
// TODO: this needs more cost tunning, check with @lotus
|
// TODO: this needs more cost tunning, check with @lotus
|
||||||
return pl.verifySealBase
|
return newGasCharge("OnVerifySeal", pl.verifySealBase, 0).WithVirtual(199954003, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnVerifyPost
|
// OnVerifyPost
|
||||||
func (pl *pricelistV0) OnVerifyPost(info abi.WindowPoStVerifyInfo) int64 {
|
func (pl *pricelistV0) OnVerifyPost(info abi.WindowPoStVerifyInfo) GasCharge {
|
||||||
// TODO: this needs more cost tunning, check with @lotus
|
// TODO: this needs more cost tunning, check with @lotus
|
||||||
return pl.verifyPostBase
|
return newGasCharge("OnVerifyPost", pl.verifyPostBase, 0).WithVirtual(2629471704, 0).WithExtra(len(info.ChallengedSectors))
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnVerifyConsensusFault
|
// OnVerifyConsensusFault
|
||||||
func (pl *pricelistV0) OnVerifyConsensusFault() int64 {
|
func (pl *pricelistV0) OnVerifyConsensusFault() GasCharge {
|
||||||
return pl.verifyConsensusFault
|
return newGasCharge("OnVerifyConsensusFault", pl.verifyConsensusFault, 0).WithVirtual(551935, 0)
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-8
@@ -32,7 +32,7 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
type invoker struct {
|
type Invoker struct {
|
||||||
builtInCode map[cid.Cid]nativeCode
|
builtInCode map[cid.Cid]nativeCode
|
||||||
builtInState map[cid.Cid]reflect.Type
|
builtInState map[cid.Cid]reflect.Type
|
||||||
}
|
}
|
||||||
@@ -40,8 +40,8 @@ type invoker struct {
|
|||||||
type invokeFunc func(rt runtime.Runtime, params []byte) ([]byte, aerrors.ActorError)
|
type invokeFunc func(rt runtime.Runtime, params []byte) ([]byte, aerrors.ActorError)
|
||||||
type nativeCode []invokeFunc
|
type nativeCode []invokeFunc
|
||||||
|
|
||||||
func NewInvoker() *invoker {
|
func NewInvoker() *Invoker {
|
||||||
inv := &invoker{
|
inv := &Invoker{
|
||||||
builtInCode: make(map[cid.Cid]nativeCode),
|
builtInCode: make(map[cid.Cid]nativeCode),
|
||||||
builtInState: make(map[cid.Cid]reflect.Type),
|
builtInState: make(map[cid.Cid]reflect.Type),
|
||||||
}
|
}
|
||||||
@@ -62,7 +62,7 @@ func NewInvoker() *invoker {
|
|||||||
return inv
|
return inv
|
||||||
}
|
}
|
||||||
|
|
||||||
func (inv *invoker) Invoke(codeCid cid.Cid, rt runtime.Runtime, method abi.MethodNum, params []byte) ([]byte, aerrors.ActorError) {
|
func (inv *Invoker) Invoke(codeCid cid.Cid, rt runtime.Runtime, method abi.MethodNum, params []byte) ([]byte, aerrors.ActorError) {
|
||||||
|
|
||||||
code, ok := inv.builtInCode[codeCid]
|
code, ok := inv.builtInCode[codeCid]
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -76,7 +76,7 @@ func (inv *invoker) Invoke(codeCid cid.Cid, rt runtime.Runtime, method abi.Metho
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (inv *invoker) Register(c cid.Cid, instance Invokee, state interface{}) {
|
func (inv *Invoker) Register(c cid.Cid, instance Invokee, state interface{}) {
|
||||||
code, err := inv.transform(instance)
|
code, err := inv.transform(instance)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(xerrors.Errorf("%s: %w", string(c.Hash()), err))
|
panic(xerrors.Errorf("%s: %w", string(c.Hash()), err))
|
||||||
@@ -89,9 +89,7 @@ type Invokee interface {
|
|||||||
Exports() []interface{}
|
Exports() []interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
var tAError = reflect.TypeOf((*aerrors.ActorError)(nil)).Elem()
|
func (*Invoker) transform(instance Invokee) (nativeCode, error) {
|
||||||
|
|
||||||
func (*invoker) transform(instance Invokee) (nativeCode, error) {
|
|
||||||
itype := reflect.TypeOf(instance)
|
itype := reflect.TypeOf(instance)
|
||||||
exports := instance.Exports()
|
exports := instance.Exports()
|
||||||
for i, m := range exports {
|
for i, m := range exports {
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ func (basicContract) InvokeSomething10(rt runtime.Runtime, params *basicParams)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestInvokerBasic(t *testing.T) {
|
func TestInvokerBasic(t *testing.T) {
|
||||||
inv := invoker{}
|
inv := Invoker{}
|
||||||
code, err := inv.transform(basicContract{})
|
code, err := inv.transform(basicContract{})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -2,6 +2,7 @@ package vm
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors"
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
"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"
|
||||||
@@ -27,7 +28,7 @@ func init() {
|
|||||||
|
|
||||||
var EmptyObjectCid cid.Cid
|
var EmptyObjectCid cid.Cid
|
||||||
|
|
||||||
// Creates account actors from only BLS/SECP256K1 addresses.
|
// TryCreateAccountActor creates account actors from only BLS/SECP256K1 addresses.
|
||||||
func TryCreateAccountActor(rt *Runtime, addr address.Address) (*types.Actor, aerrors.ActorError) {
|
func TryCreateAccountActor(rt *Runtime, addr address.Address) (*types.Actor, aerrors.ActorError) {
|
||||||
addrID, err := rt.state.RegisterNewAddress(addr)
|
addrID, err := rt.state.RegisterNewAddress(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+129
-81
@@ -5,6 +5,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
gruntime "runtime"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||||
@@ -50,10 +52,12 @@ type Runtime struct {
|
|||||||
origin address.Address
|
origin address.Address
|
||||||
originNonce uint64
|
originNonce uint64
|
||||||
|
|
||||||
internalExecutions []*types.ExecutionResult
|
executionTrace types.ExecutionTrace
|
||||||
numActorsCreated uint64
|
numActorsCreated uint64
|
||||||
allowInternal bool
|
allowInternal bool
|
||||||
callerValidated bool
|
callerValidated bool
|
||||||
|
lastGasChargeTime time.Time
|
||||||
|
lastGasCharge *types.GasTrace
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rt *Runtime) TotalFilCircSupply() abi.TokenAmount {
|
func (rt *Runtime) TotalFilCircSupply() abi.TokenAmount {
|
||||||
@@ -106,8 +110,8 @@ type notFoundErr interface {
|
|||||||
IsNotFound() bool
|
IsNotFound() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *Runtime) Get(c cid.Cid, o vmr.CBORUnmarshaler) bool {
|
func (rt *Runtime) Get(c cid.Cid, o vmr.CBORUnmarshaler) bool {
|
||||||
if err := rs.cst.Get(context.TODO(), c, o); err != nil {
|
if err := rt.cst.Get(context.TODO(), c, o); err != nil {
|
||||||
var nfe notFoundErr
|
var nfe notFoundErr
|
||||||
if xerrors.As(err, &nfe) && nfe.IsNotFound() {
|
if xerrors.As(err, &nfe) && nfe.IsNotFound() {
|
||||||
if xerrors.As(err, new(cbor.SerializationError)) {
|
if xerrors.As(err, new(cbor.SerializationError)) {
|
||||||
@@ -121,8 +125,8 @@ func (rs *Runtime) Get(c cid.Cid, o vmr.CBORUnmarshaler) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *Runtime) Put(x vmr.CBORMarshaler) cid.Cid {
|
func (rt *Runtime) Put(x vmr.CBORMarshaler) cid.Cid {
|
||||||
c, err := rs.cst.Put(context.TODO(), x)
|
c, err := rt.cst.Put(context.TODO(), x)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if xerrors.As(err, new(cbor.SerializationError)) {
|
if xerrors.As(err, new(cbor.SerializationError)) {
|
||||||
panic(aerrors.Newf(exitcode.ErrSerialization, "failed to marshal cbor object %s", err))
|
panic(aerrors.Newf(exitcode.ErrSerialization, "failed to marshal cbor object %s", err))
|
||||||
@@ -134,11 +138,11 @@ func (rs *Runtime) Put(x vmr.CBORMarshaler) cid.Cid {
|
|||||||
|
|
||||||
var _ vmr.Runtime = (*Runtime)(nil)
|
var _ vmr.Runtime = (*Runtime)(nil)
|
||||||
|
|
||||||
func (rs *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.ActorError) {
|
func (rt *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.ActorError) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
if ar, ok := r.(aerrors.ActorError); ok {
|
if ar, ok := r.(aerrors.ActorError); ok {
|
||||||
log.Errorf("VM.Call failure: %+v", ar)
|
log.Warnf("VM.Call failure: %+v", ar)
|
||||||
aerr = ar
|
aerr = ar
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -149,8 +153,8 @@ func (rs *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.Act
|
|||||||
|
|
||||||
ret := f()
|
ret := f()
|
||||||
|
|
||||||
if !rs.callerValidated {
|
if !rt.callerValidated {
|
||||||
rs.Abortf(exitcode.SysErrorIllegalActor, "Caller MUST be validated during method execution")
|
rt.Abortf(exitcode.SysErrorIllegalActor, "Caller MUST be validated during method execution")
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ret := ret.(type) {
|
switch ret := ret.(type) {
|
||||||
@@ -171,25 +175,25 @@ func (rs *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.Act
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *Runtime) Message() vmr.Message {
|
func (rt *Runtime) Message() vmr.Message {
|
||||||
return rs.vmsg
|
return rt.vmsg
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *Runtime) ValidateImmediateCallerAcceptAny() {
|
func (rt *Runtime) ValidateImmediateCallerAcceptAny() {
|
||||||
rs.abortIfAlreadyValidated()
|
rt.abortIfAlreadyValidated()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *Runtime) CurrentBalance() abi.TokenAmount {
|
func (rt *Runtime) CurrentBalance() abi.TokenAmount {
|
||||||
b, err := rs.GetBalance(rs.Message().Receiver())
|
b, err := rt.GetBalance(rt.Message().Receiver())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rs.Abortf(err.RetCode(), "get current balance: %v", err)
|
rt.Abortf(err.RetCode(), "get current balance: %v", err)
|
||||||
}
|
}
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *Runtime) GetActorCodeCID(addr address.Address) (ret cid.Cid, ok bool) {
|
func (rt *Runtime) GetActorCodeCID(addr address.Address) (ret cid.Cid, ok bool) {
|
||||||
act, err := rs.state.GetActor(addr)
|
act, err := rt.state.GetActor(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if xerrors.Is(err, types.ErrActorNotFound) {
|
if xerrors.Is(err, types.ErrActorNotFound) {
|
||||||
return cid.Undef, false
|
return cid.Undef, false
|
||||||
@@ -209,8 +213,8 @@ func (rt *Runtime) GetRandomness(personalization crypto.DomainSeparationTag, ran
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *Runtime) Store() vmr.Store {
|
func (rt *Runtime) Store() vmr.Store {
|
||||||
return rs
|
return rt
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rt *Runtime) NewActorAddress() address.Address {
|
func (rt *Runtime) NewActorAddress() address.Address {
|
||||||
@@ -235,12 +239,12 @@ func (rt *Runtime) NewActorAddress() address.Address {
|
|||||||
return addr
|
return addr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rt *Runtime) CreateActor(codeId cid.Cid, address address.Address) {
|
func (rt *Runtime) CreateActor(codeID cid.Cid, address address.Address) {
|
||||||
if !builtin.IsBuiltinActor(codeId) {
|
if !builtin.IsBuiltinActor(codeID) {
|
||||||
rt.Abortf(exitcode.SysErrorIllegalArgument, "Can only create built-in actors.")
|
rt.Abortf(exitcode.SysErrorIllegalArgument, "Can only create built-in actors.")
|
||||||
}
|
}
|
||||||
|
|
||||||
if builtin.IsSingletonActor(codeId) {
|
if builtin.IsSingletonActor(codeID) {
|
||||||
rt.Abortf(exitcode.SysErrorIllegalArgument, "Can only have one instance of singleton actors.")
|
rt.Abortf(exitcode.SysErrorIllegalArgument, "Can only have one instance of singleton actors.")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,10 +253,10 @@ func (rt *Runtime) CreateActor(codeId cid.Cid, address address.Address) {
|
|||||||
rt.Abortf(exitcode.SysErrorIllegalArgument, "Actor address already exists")
|
rt.Abortf(exitcode.SysErrorIllegalArgument, "Actor address already exists")
|
||||||
}
|
}
|
||||||
|
|
||||||
rt.ChargeGas(rt.Pricelist().OnCreateActor())
|
rt.chargeGas(rt.Pricelist().OnCreateActor())
|
||||||
|
|
||||||
err = rt.state.SetActor(address, &types.Actor{
|
err = rt.state.SetActor(address, &types.Actor{
|
||||||
Code: codeId,
|
Code: codeID,
|
||||||
Head: EmptyObjectCid,
|
Head: EmptyObjectCid,
|
||||||
Nonce: 0,
|
Nonce: 0,
|
||||||
Balance: big.Zero(),
|
Balance: big.Zero(),
|
||||||
@@ -260,10 +264,11 @@ func (rt *Runtime) CreateActor(codeId cid.Cid, address address.Address) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(aerrors.Fatalf("creating actor entry: %v", err))
|
panic(aerrors.Fatalf("creating actor entry: %v", err))
|
||||||
}
|
}
|
||||||
|
_ = rt.chargeGasSafe(gasOnActorExec)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rt *Runtime) DeleteActor(addr address.Address) {
|
func (rt *Runtime) DeleteActor(addr address.Address) {
|
||||||
rt.ChargeGas(rt.Pricelist().OnDeleteActor())
|
rt.chargeGas(rt.Pricelist().OnDeleteActor())
|
||||||
act, err := rt.state.GetActor(rt.Message().Receiver())
|
act, err := rt.state.GetActor(rt.Message().Receiver())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if xerrors.Is(err, types.ErrActorNotFound) {
|
if xerrors.Is(err, types.ErrActorNotFound) {
|
||||||
@@ -280,14 +285,14 @@ func (rt *Runtime) DeleteActor(addr address.Address) {
|
|||||||
if err := rt.state.DeleteActor(rt.Message().Receiver()); err != nil {
|
if err := rt.state.DeleteActor(rt.Message().Receiver()); err != nil {
|
||||||
panic(aerrors.Fatalf("failed to delete actor: %s", err))
|
panic(aerrors.Fatalf("failed to delete actor: %s", err))
|
||||||
}
|
}
|
||||||
|
_ = rt.chargeGasSafe(gasOnActorExec)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *Runtime) Syscalls() vmr.Syscalls {
|
func (rt *Runtime) Syscalls() vmr.Syscalls {
|
||||||
// TODO: Make sure this is wrapped in something that charges gas for each of the calls
|
return rt.sys
|
||||||
return rs.sys
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *Runtime) StartSpan(name string) vmr.TraceSpan {
|
func (rt *Runtime) StartSpan(name string) vmr.TraceSpan {
|
||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,12 +312,12 @@ func (rt *Runtime) Context() context.Context {
|
|||||||
return rt.ctx
|
return rt.ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *Runtime) Abortf(code exitcode.ExitCode, msg string, args ...interface{}) {
|
func (rt *Runtime) Abortf(code exitcode.ExitCode, msg string, args ...interface{}) {
|
||||||
log.Error("Abortf: ", fmt.Sprintf(msg, args...))
|
log.Warnf("Abortf: " + fmt.Sprintf(msg, args...))
|
||||||
panic(aerrors.NewfSkip(2, code, msg, args...))
|
panic(aerrors.NewfSkip(2, code, msg, args...))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *Runtime) AbortStateMsg(msg string) {
|
func (rt *Runtime) AbortStateMsg(msg string) {
|
||||||
panic(aerrors.NewfSkip(3, 101, msg))
|
panic(aerrors.NewfSkip(3, 101, msg))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,8 +335,8 @@ func (rt *Runtime) ValidateImmediateCallerType(ts ...cid.Cid) {
|
|||||||
rt.Abortf(exitcode.SysErrForbidden, "caller cid type %q was not one of %v", callerCid, ts)
|
rt.Abortf(exitcode.SysErrForbidden, "caller cid type %q was not one of %v", callerCid, ts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *Runtime) CurrEpoch() abi.ChainEpoch {
|
func (rt *Runtime) CurrEpoch() abi.ChainEpoch {
|
||||||
return rs.height
|
return rt.height
|
||||||
}
|
}
|
||||||
|
|
||||||
type dumbWrapperType struct {
|
type dumbWrapperType struct {
|
||||||
@@ -342,20 +347,20 @@ func (dwt *dumbWrapperType) Into(um vmr.CBORUnmarshaler) error {
|
|||||||
return um.UnmarshalCBOR(bytes.NewReader(dwt.val))
|
return um.UnmarshalCBOR(bytes.NewReader(dwt.val))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *Runtime) Send(to address.Address, method abi.MethodNum, m vmr.CBORMarshaler, value abi.TokenAmount) (vmr.SendReturn, exitcode.ExitCode) {
|
func (rt *Runtime) Send(to address.Address, method abi.MethodNum, m vmr.CBORMarshaler, value abi.TokenAmount) (vmr.SendReturn, exitcode.ExitCode) {
|
||||||
if !rs.allowInternal {
|
if !rt.allowInternal {
|
||||||
rs.Abortf(exitcode.SysErrorIllegalActor, "runtime.Send() is currently disallowed")
|
rt.Abortf(exitcode.SysErrorIllegalActor, "runtime.Send() is currently disallowed")
|
||||||
}
|
}
|
||||||
var params []byte
|
var params []byte
|
||||||
if m != nil {
|
if m != nil {
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
if err := m.MarshalCBOR(buf); err != nil {
|
if err := m.MarshalCBOR(buf); err != nil {
|
||||||
rs.Abortf(exitcode.SysErrInvalidParameters, "failed to marshal input parameters: %s", err)
|
rt.Abortf(exitcode.SysErrInvalidParameters, "failed to marshal input parameters: %s", err)
|
||||||
}
|
}
|
||||||
params = buf.Bytes()
|
params = buf.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
ret, err := rs.internalSend(rs.Message().Receiver(), to, method, value, params)
|
ret, err := rt.internalSend(rt.Message().Receiver(), to, method, value, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err.IsFatal() {
|
if err.IsFatal() {
|
||||||
panic(err)
|
panic(err)
|
||||||
@@ -363,10 +368,13 @@ func (rs *Runtime) Send(to address.Address, method abi.MethodNum, m vmr.CBORMars
|
|||||||
log.Warnf("vmctx send failed: to: %s, method: %d: ret: %d, err: %s", to, method, ret, err)
|
log.Warnf("vmctx send failed: to: %s, method: %d: ret: %d, err: %s", to, method, ret, err)
|
||||||
return nil, err.RetCode()
|
return nil, err.RetCode()
|
||||||
}
|
}
|
||||||
|
_ = rt.chargeGasSafe(gasOnActorExec)
|
||||||
return &dumbWrapperType{ret}, 0
|
return &dumbWrapperType{ret}, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rt *Runtime) internalSend(from, to address.Address, method abi.MethodNum, value types.BigInt, params []byte) ([]byte, aerrors.ActorError) {
|
func (rt *Runtime) internalSend(from, to address.Address, method abi.MethodNum, value types.BigInt, params []byte) ([]byte, aerrors.ActorError) {
|
||||||
|
|
||||||
|
start := time.Now()
|
||||||
ctx, span := trace.StartSpan(rt.ctx, "vmc.Send")
|
ctx, span := trace.StartSpan(rt.ctx, "vmc.Send")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
if span.IsRecordingEvents() {
|
if span.IsRecordingEvents() {
|
||||||
@@ -392,78 +400,62 @@ func (rt *Runtime) internalSend(from, to address.Address, method abi.MethodNum,
|
|||||||
}
|
}
|
||||||
defer st.ClearSnapshot()
|
defer st.ClearSnapshot()
|
||||||
|
|
||||||
ret, errSend, subrt := rt.vm.send(ctx, msg, rt, 0)
|
ret, errSend, subrt := rt.vm.send(ctx, msg, rt, nil, start)
|
||||||
if errSend != nil {
|
if errSend != nil {
|
||||||
if errRevert := st.Revert(); errRevert != nil {
|
if errRevert := st.Revert(); errRevert != nil {
|
||||||
return nil, aerrors.Escalate(errRevert, "failed to revert state tree after failed subcall")
|
return nil, aerrors.Escalate(errRevert, "failed to revert state tree after failed subcall")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mr := types.MessageReceipt{
|
|
||||||
ExitCode: aerrors.RetCode(errSend),
|
|
||||||
Return: ret,
|
|
||||||
GasUsed: 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
er := types.ExecutionResult{
|
|
||||||
Msg: msg,
|
|
||||||
MsgRct: &mr,
|
|
||||||
}
|
|
||||||
|
|
||||||
if errSend != nil {
|
|
||||||
er.Error = errSend.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
if subrt != nil {
|
if subrt != nil {
|
||||||
er.Subcalls = subrt.internalExecutions
|
|
||||||
rt.numActorsCreated = subrt.numActorsCreated
|
rt.numActorsCreated = subrt.numActorsCreated
|
||||||
}
|
}
|
||||||
rt.internalExecutions = append(rt.internalExecutions, &er)
|
rt.executionTrace.Subcalls = append(rt.executionTrace.Subcalls, subrt.executionTrace)
|
||||||
return ret, errSend
|
return ret, errSend
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *Runtime) State() vmr.StateHandle {
|
func (rt *Runtime) State() vmr.StateHandle {
|
||||||
return &shimStateHandle{rs: rs}
|
return &shimStateHandle{rt: rt}
|
||||||
}
|
}
|
||||||
|
|
||||||
type shimStateHandle struct {
|
type shimStateHandle struct {
|
||||||
rs *Runtime
|
rt *Runtime
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ssh *shimStateHandle) Create(obj vmr.CBORMarshaler) {
|
func (ssh *shimStateHandle) Create(obj vmr.CBORMarshaler) {
|
||||||
c := ssh.rs.Put(obj)
|
c := ssh.rt.Put(obj)
|
||||||
// TODO: handle error below
|
// TODO: handle error below
|
||||||
ssh.rs.stateCommit(EmptyObjectCid, c)
|
ssh.rt.stateCommit(EmptyObjectCid, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ssh *shimStateHandle) Readonly(obj vmr.CBORUnmarshaler) {
|
func (ssh *shimStateHandle) Readonly(obj vmr.CBORUnmarshaler) {
|
||||||
act, err := ssh.rs.state.GetActor(ssh.rs.Message().Receiver())
|
act, err := ssh.rt.state.GetActor(ssh.rt.Message().Receiver())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ssh.rs.Abortf(exitcode.SysErrorIllegalArgument, "failed to get actor for Readonly state: %s", err)
|
ssh.rt.Abortf(exitcode.SysErrorIllegalArgument, "failed to get actor for Readonly state: %s", err)
|
||||||
}
|
}
|
||||||
ssh.rs.Get(act.Head, obj)
|
ssh.rt.Get(act.Head, obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ssh *shimStateHandle) Transaction(obj vmr.CBORer, f func() interface{}) interface{} {
|
func (ssh *shimStateHandle) Transaction(obj vmr.CBORer, f func() interface{}) interface{} {
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
ssh.rs.Abortf(exitcode.SysErrorIllegalActor, "Must not pass nil to Transaction()")
|
ssh.rt.Abortf(exitcode.SysErrorIllegalActor, "Must not pass nil to Transaction()")
|
||||||
}
|
}
|
||||||
|
|
||||||
act, err := ssh.rs.state.GetActor(ssh.rs.Message().Receiver())
|
act, err := ssh.rt.state.GetActor(ssh.rt.Message().Receiver())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ssh.rs.Abortf(exitcode.SysErrorIllegalActor, "failed to get actor for Transaction: %s", err)
|
ssh.rt.Abortf(exitcode.SysErrorIllegalActor, "failed to get actor for Transaction: %s", err)
|
||||||
}
|
}
|
||||||
baseState := act.Head
|
baseState := act.Head
|
||||||
ssh.rs.Get(baseState, obj)
|
ssh.rt.Get(baseState, obj)
|
||||||
|
|
||||||
ssh.rs.allowInternal = false
|
ssh.rt.allowInternal = false
|
||||||
out := f()
|
out := f()
|
||||||
ssh.rs.allowInternal = true
|
ssh.rt.allowInternal = true
|
||||||
|
|
||||||
c := ssh.rs.Put(obj)
|
c := ssh.rt.Put(obj)
|
||||||
|
|
||||||
// TODO: handle error below
|
// TODO: handle error below
|
||||||
ssh.rs.stateCommit(baseState, c)
|
ssh.rt.stateCommit(baseState, c)
|
||||||
|
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
@@ -500,22 +492,78 @@ func (rt *Runtime) stateCommit(oldh, newh cid.Cid) aerrors.ActorError {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rt *Runtime) ChargeGas(toUse int64) {
|
func (rt *Runtime) finilizeGasTracing() {
|
||||||
err := rt.chargeGasSafe(toUse)
|
if rt.lastGasCharge != nil {
|
||||||
|
rt.lastGasCharge.TimeTaken = time.Since(rt.lastGasChargeTime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChargeGas is spec actors function
|
||||||
|
func (rt *Runtime) ChargeGas(name string, compute int64, virtual int64) {
|
||||||
|
err := rt.chargeGasInternal(newGasCharge(name, compute, 0).WithVirtual(virtual, 0), 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rt *Runtime) chargeGasSafe(toUse int64) aerrors.ActorError {
|
func (rt *Runtime) chargeGas(gas GasCharge) {
|
||||||
|
err := rt.chargeGasInternal(gas, 1)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rt *Runtime) chargeGasFunc(skip int) func(GasCharge) {
|
||||||
|
return func(gas GasCharge) {
|
||||||
|
err := rt.chargeGasInternal(gas, 1+skip)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rt *Runtime) chargeGasInternal(gas GasCharge, skip int) aerrors.ActorError {
|
||||||
|
toUse := gas.Total()
|
||||||
|
var callers [10]uintptr
|
||||||
|
cout := gruntime.Callers(2+skip, callers[:])
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
if rt.lastGasCharge != nil {
|
||||||
|
rt.lastGasCharge.TimeTaken = now.Sub(rt.lastGasChargeTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
gasTrace := types.GasTrace{
|
||||||
|
Name: gas.Name,
|
||||||
|
Extra: gas.Extra,
|
||||||
|
|
||||||
|
TotalGas: toUse,
|
||||||
|
ComputeGas: gas.ComputeGas,
|
||||||
|
StorageGas: gas.StorageGas,
|
||||||
|
|
||||||
|
TotalVirtualGas: gas.VirtualCompute*GasComputeMulti + gas.VirtualStorage*GasStorageMulti,
|
||||||
|
VirtualComputeGas: gas.VirtualCompute,
|
||||||
|
VirtualStorageGas: gas.VirtualStorage,
|
||||||
|
|
||||||
|
Callers: callers[:cout],
|
||||||
|
}
|
||||||
|
rt.executionTrace.GasCharges = append(rt.executionTrace.GasCharges, &gasTrace)
|
||||||
|
rt.lastGasChargeTime = now
|
||||||
|
rt.lastGasCharge = &gasTrace
|
||||||
|
|
||||||
if rt.gasUsed+toUse > rt.gasAvailable {
|
if rt.gasUsed+toUse > rt.gasAvailable {
|
||||||
rt.gasUsed = rt.gasAvailable
|
rt.gasUsed = rt.gasAvailable
|
||||||
return aerrors.Newf(exitcode.SysErrOutOfGas, "not enough gas: used=%d, available=%d", rt.gasUsed, rt.gasAvailable)
|
return aerrors.Newf(exitcode.SysErrOutOfGas, "not enough gas: used=%d, available=%d",
|
||||||
|
rt.gasUsed, rt.gasAvailable)
|
||||||
}
|
}
|
||||||
rt.gasUsed += toUse
|
rt.gasUsed += toUse
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rt *Runtime) chargeGasSafe(gas GasCharge) aerrors.ActorError {
|
||||||
|
return rt.chargeGasInternal(gas, 1)
|
||||||
|
}
|
||||||
|
|
||||||
func (rt *Runtime) Pricelist() Pricelist {
|
func (rt *Runtime) Pricelist() Pricelist {
|
||||||
return rt.pricelist
|
return rt.pricelist
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-18
@@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
goruntime "runtime"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
@@ -42,7 +43,7 @@ type syscallShim struct {
|
|||||||
verifier ffiwrapper.Verifier
|
verifier ffiwrapper.Verifier
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *syscallShim) ComputeUnsealedSectorCID(st abi.RegisteredProof, pieces []abi.PieceInfo) (cid.Cid, error) {
|
func (ss *syscallShim) ComputeUnsealedSectorCID(st abi.RegisteredSealProof, pieces []abi.PieceInfo) (cid.Cid, error) {
|
||||||
var sum abi.PaddedPieceSize
|
var sum abi.PaddedPieceSize
|
||||||
for _, p := range pieces {
|
for _, p := range pieces {
|
||||||
sum += p.Size
|
sum += p.Size
|
||||||
@@ -114,7 +115,7 @@ func (ss *syscallShim) VerifyConsensusFault(a, b, extra []byte) (*runtime.Consen
|
|||||||
// (b) time-offset mining fault
|
// (b) time-offset mining fault
|
||||||
// strictly speaking no need to compare heights based on double fork mining check above,
|
// strictly speaking no need to compare heights based on double fork mining check above,
|
||||||
// but at same height this would be a different fault.
|
// but at same height this would be a different fault.
|
||||||
if !types.CidArrsEqual(blockA.Parents, blockB.Parents) && blockA.Height != blockB.Height {
|
if types.CidArrsEqual(blockA.Parents, blockB.Parents) && blockA.Height != blockB.Height {
|
||||||
consensusFault = &runtime.ConsensusFault{
|
consensusFault = &runtime.ConsensusFault{
|
||||||
Target: blockA.Miner,
|
Target: blockA.Miner,
|
||||||
Epoch: blockB.Height,
|
Epoch: blockB.Height,
|
||||||
@@ -158,7 +159,7 @@ func (ss *syscallShim) VerifyConsensusFault(a, b, extra []byte) (*runtime.Consen
|
|||||||
}
|
}
|
||||||
|
|
||||||
if sigErr := ss.VerifyBlockSig(&blockB); sigErr != nil {
|
if sigErr := ss.VerifyBlockSig(&blockB); sigErr != nil {
|
||||||
return nil, xerrors.Errorf("cannot verify first block sig: %w", sigErr)
|
return nil, xerrors.Errorf("cannot verify second block sig: %w", sigErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
return consensusFault, nil
|
return consensusFault, nil
|
||||||
@@ -184,7 +185,7 @@ func (ss *syscallShim) VerifyBlockSig(blk *types.BlockHeader) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := sigs.CheckBlockSignature(blk, ss.ctx, waddr); err != nil {
|
if err := sigs.CheckBlockSignature(ss.ctx, blk, waddr); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,20 +203,6 @@ func (ss *syscallShim) VerifyPoSt(proof abi.WindowPoStVerifyInfo) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func cidToCommD(c cid.Cid) [32]byte {
|
|
||||||
b := c.Bytes()
|
|
||||||
var out [32]byte
|
|
||||||
copy(out[:], b[len(b)-32:])
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
func cidToCommR(c cid.Cid) [32]byte {
|
|
||||||
b := c.Bytes()
|
|
||||||
var out [32]byte
|
|
||||||
copy(out[:], b[len(b)-32:])
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ss *syscallShim) VerifySeal(info abi.SealVerifyInfo) error {
|
func (ss *syscallShim) VerifySeal(info abi.SealVerifyInfo) error {
|
||||||
//_, span := trace.StartSpan(ctx, "ValidatePoRep")
|
//_, span := trace.StartSpan(ctx, "ValidatePoRep")
|
||||||
//defer span.End()
|
//defer span.End()
|
||||||
@@ -254,9 +241,13 @@ func (ss *syscallShim) VerifySignature(sig crypto.Signature, addr address.Addres
|
|||||||
return sigs.Verify(&sig, kaddr, input)
|
return sigs.Verify(&sig, kaddr, input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var BatchSealVerifyParallelism = goruntime.NumCPU()
|
||||||
|
|
||||||
func (ss *syscallShim) BatchVerifySeals(inp map[address.Address][]abi.SealVerifyInfo) (map[address.Address][]bool, error) {
|
func (ss *syscallShim) BatchVerifySeals(inp map[address.Address][]abi.SealVerifyInfo) (map[address.Address][]bool, error) {
|
||||||
out := make(map[address.Address][]bool)
|
out := make(map[address.Address][]bool)
|
||||||
|
|
||||||
|
sema := make(chan struct{}, BatchSealVerifyParallelism)
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
for addr, seals := range inp {
|
for addr, seals := range inp {
|
||||||
results := make([]bool, len(seals))
|
results := make([]bool, len(seals))
|
||||||
@@ -266,12 +257,16 @@ func (ss *syscallShim) BatchVerifySeals(inp map[address.Address][]abi.SealVerify
|
|||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func(ma address.Address, ix int, svi abi.SealVerifyInfo, res []bool) {
|
go func(ma address.Address, ix int, svi abi.SealVerifyInfo, res []bool) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
sema <- struct{}{}
|
||||||
|
|
||||||
if err := ss.VerifySeal(svi); err != nil {
|
if err := ss.VerifySeal(svi); err != nil {
|
||||||
log.Warnw("seal verify in batch failed", "miner", ma, "index", ix, "err", err)
|
log.Warnw("seal verify in batch failed", "miner", ma, "index", ix, "err", err)
|
||||||
res[ix] = false
|
res[ix] = false
|
||||||
} else {
|
} else {
|
||||||
res[ix] = true
|
res[ix] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<-sema
|
||||||
}(addr, i, s, results)
|
}(addr, i, s, results)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+91
-52
@@ -35,6 +35,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var log = logging.Logger("vm")
|
var log = logging.Logger("vm")
|
||||||
|
var gasOnActorExec = newGasCharge("OnActorExec", 0, 0)
|
||||||
|
|
||||||
// ResolveToKeyAddr returns the public key type of address (`BLS`/`SECP256K1`) of an account actor identified by `addr`.
|
// ResolveToKeyAddr returns the public key type of address (`BLS`/`SECP256K1`) of an account actor identified by `addr`.
|
||||||
func ResolveToKeyAddr(state types.StateTree, cst cbor.IpldStore, addr address.Address) (address.Address, aerrors.ActorError) {
|
func ResolveToKeyAddr(state types.StateTree, cst cbor.IpldStore, addr address.Address) (address.Address, aerrors.ActorError) {
|
||||||
@@ -62,17 +63,19 @@ func ResolveToKeyAddr(state types.StateTree, cst cbor.IpldStore, addr address.Ad
|
|||||||
var _ cbor.IpldBlockstore = (*gasChargingBlocks)(nil)
|
var _ cbor.IpldBlockstore = (*gasChargingBlocks)(nil)
|
||||||
|
|
||||||
type gasChargingBlocks struct {
|
type gasChargingBlocks struct {
|
||||||
chargeGas func(int64)
|
chargeGas func(GasCharge)
|
||||||
pricelist Pricelist
|
pricelist Pricelist
|
||||||
under cbor.IpldBlockstore
|
under cbor.IpldBlockstore
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *gasChargingBlocks) Get(c cid.Cid) (block.Block, error) {
|
func (bs *gasChargingBlocks) Get(c cid.Cid) (block.Block, error) {
|
||||||
|
bs.chargeGas(newGasCharge("OnIpldGetStart", 0, 0))
|
||||||
blk, err := bs.under.Get(c)
|
blk, err := bs.under.Get(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, aerrors.Escalate(err, "failed to get block from blockstore")
|
return nil, aerrors.Escalate(err, "failed to get block from blockstore")
|
||||||
}
|
}
|
||||||
bs.chargeGas(bs.pricelist.OnIpldGet(len(blk.RawData())))
|
bs.chargeGas(bs.pricelist.OnIpldGet(len(blk.RawData())))
|
||||||
|
bs.chargeGas(gasOnActorExec)
|
||||||
|
|
||||||
return blk, nil
|
return blk, nil
|
||||||
}
|
}
|
||||||
@@ -83,6 +86,7 @@ func (bs *gasChargingBlocks) Put(blk block.Block) error {
|
|||||||
if err := bs.under.Put(blk); err != nil {
|
if err := bs.under.Put(blk); err != nil {
|
||||||
return aerrors.Escalate(err, "failed to write data to disk")
|
return aerrors.Escalate(err, "failed to write data to disk")
|
||||||
}
|
}
|
||||||
|
bs.chargeGas(gasOnActorExec)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,15 +106,16 @@ func (vm *VM) makeRuntime(ctx context.Context, msg *types.Message, origin addres
|
|||||||
pricelist: PricelistByEpoch(vm.blockHeight),
|
pricelist: PricelistByEpoch(vm.blockHeight),
|
||||||
allowInternal: true,
|
allowInternal: true,
|
||||||
callerValidated: false,
|
callerValidated: false,
|
||||||
|
executionTrace: types.ExecutionTrace{Msg: msg},
|
||||||
}
|
}
|
||||||
|
|
||||||
rt.cst = &cbor.BasicIpldStore{
|
rt.cst = &cbor.BasicIpldStore{
|
||||||
Blocks: &gasChargingBlocks{rt.ChargeGas, rt.pricelist, vm.cst.Blocks},
|
Blocks: &gasChargingBlocks{rt.chargeGasFunc(2), rt.pricelist, vm.cst.Blocks},
|
||||||
Atlas: vm.cst.Atlas,
|
Atlas: vm.cst.Atlas,
|
||||||
}
|
}
|
||||||
rt.sys = pricedSyscalls{
|
rt.sys = pricedSyscalls{
|
||||||
under: vm.Syscalls,
|
under: vm.Syscalls,
|
||||||
chargeGas: rt.ChargeGas,
|
chargeGas: rt.chargeGasFunc(1),
|
||||||
pl: rt.pricelist,
|
pl: rt.pricelist,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,7 +136,7 @@ type VM struct {
|
|||||||
cst *cbor.BasicIpldStore
|
cst *cbor.BasicIpldStore
|
||||||
buf *bufbstore.BufferedBS
|
buf *bufbstore.BufferedBS
|
||||||
blockHeight abi.ChainEpoch
|
blockHeight abi.ChainEpoch
|
||||||
inv *invoker
|
inv *Invoker
|
||||||
rand Rand
|
rand Rand
|
||||||
|
|
||||||
Syscalls runtime.Syscalls
|
Syscalls runtime.Syscalls
|
||||||
@@ -163,63 +168,93 @@ type Rand interface {
|
|||||||
|
|
||||||
type ApplyRet struct {
|
type ApplyRet struct {
|
||||||
types.MessageReceipt
|
types.MessageReceipt
|
||||||
ActorErr aerrors.ActorError
|
ActorErr aerrors.ActorError
|
||||||
Penalty types.BigInt
|
Penalty types.BigInt
|
||||||
InternalExecutions []*types.ExecutionResult
|
ExecutionTrace types.ExecutionTrace
|
||||||
Duration time.Duration
|
Duration time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime,
|
func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime,
|
||||||
gasCharge int64) ([]byte, aerrors.ActorError, *Runtime) {
|
gasCharge *GasCharge, start time.Time) ([]byte, aerrors.ActorError, *Runtime) {
|
||||||
|
|
||||||
st := vm.cstate
|
st := vm.cstate
|
||||||
gasUsed := gasCharge
|
|
||||||
|
|
||||||
origin := msg.From
|
origin := msg.From
|
||||||
on := msg.Nonce
|
on := msg.Nonce
|
||||||
var nac uint64 = 0
|
var nac uint64 = 0
|
||||||
|
var gasUsed int64
|
||||||
if parent != nil {
|
if parent != nil {
|
||||||
gasUsed = parent.gasUsed + gasUsed
|
gasUsed = parent.gasUsed
|
||||||
origin = parent.origin
|
origin = parent.origin
|
||||||
on = parent.originNonce
|
on = parent.originNonce
|
||||||
nac = parent.numActorsCreated
|
nac = parent.numActorsCreated
|
||||||
}
|
}
|
||||||
|
|
||||||
rt := vm.makeRuntime(ctx, msg, origin, on, gasUsed, nac)
|
rt := vm.makeRuntime(ctx, msg, origin, on, gasUsed, nac)
|
||||||
|
rt.lastGasChargeTime = start
|
||||||
if parent != nil {
|
if parent != nil {
|
||||||
|
rt.lastGasChargeTime = parent.lastGasChargeTime
|
||||||
|
rt.lastGasCharge = parent.lastGasCharge
|
||||||
defer func() {
|
defer func() {
|
||||||
parent.gasUsed = rt.gasUsed
|
parent.gasUsed = rt.gasUsed
|
||||||
|
parent.lastGasChargeTime = rt.lastGasChargeTime
|
||||||
|
parent.lastGasCharge = rt.lastGasCharge
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
if aerr := rt.chargeGasSafe(rt.Pricelist().OnMethodInvocation(msg.Value, msg.Method)); aerr != nil {
|
if gasCharge != nil {
|
||||||
return nil, aerrors.Wrap(aerr, "not enough gas for method invocation"), rt
|
if err := rt.chargeGasSafe(*gasCharge); err != nil {
|
||||||
|
// this should never happen
|
||||||
|
return nil, aerrors.Wrap(err, "not enough gas for initial message charge, this should not happen"), rt
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toActor, err := st.GetActor(msg.To)
|
ret, err := func() ([]byte, aerrors.ActorError) {
|
||||||
if err != nil {
|
if aerr := rt.chargeGasSafe(rt.Pricelist().OnMethodInvocation(msg.Value, msg.Method)); aerr != nil {
|
||||||
if xerrors.Is(err, init_.ErrAddressNotFound) {
|
return nil, aerrors.Wrap(aerr, "not enough gas for method invocation")
|
||||||
a, err := TryCreateAccountActor(rt, msg.To)
|
}
|
||||||
if err != nil {
|
|
||||||
return nil, aerrors.Wrapf(err, "could not create account"), rt
|
toActor, err := st.GetActor(msg.To)
|
||||||
|
if err != nil {
|
||||||
|
if xerrors.Is(err, init_.ErrAddressNotFound) {
|
||||||
|
a, err := TryCreateAccountActor(rt, msg.To)
|
||||||
|
if err != nil {
|
||||||
|
return nil, aerrors.Wrapf(err, "could not create account")
|
||||||
|
}
|
||||||
|
toActor = a
|
||||||
|
} else {
|
||||||
|
return nil, aerrors.Escalate(err, "getting actor")
|
||||||
}
|
}
|
||||||
toActor = a
|
|
||||||
} else {
|
|
||||||
return nil, aerrors.Escalate(err, "getting actor"), rt
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if types.BigCmp(msg.Value, types.NewInt(0)) != 0 {
|
if types.BigCmp(msg.Value, types.NewInt(0)) != 0 {
|
||||||
if err := vm.transfer(msg.From, msg.To, msg.Value); err != nil {
|
if err := vm.transfer(msg.From, msg.To, msg.Value); err != nil {
|
||||||
return nil, aerrors.Wrap(err, "failed to transfer funds"), nil
|
return nil, aerrors.Wrap(err, "failed to transfer funds")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if msg.Method != 0 {
|
||||||
|
var ret []byte
|
||||||
|
_ = rt.chargeGasSafe(gasOnActorExec)
|
||||||
|
ret, err := vm.Invoke(toActor, rt, msg.Method, msg.Params)
|
||||||
|
_ = rt.chargeGasSafe(newGasCharge("OnActorExecDone", 0, 0))
|
||||||
|
return ret, err
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}()
|
||||||
|
|
||||||
|
mr := types.MessageReceipt{
|
||||||
|
ExitCode: aerrors.RetCode(err),
|
||||||
|
Return: ret,
|
||||||
|
GasUsed: rt.gasUsed,
|
||||||
|
}
|
||||||
|
rt.executionTrace.MsgRct = &mr
|
||||||
|
rt.executionTrace.Duration = time.Since(start)
|
||||||
|
if err != nil {
|
||||||
|
rt.executionTrace.Error = err.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
if msg.Method != 0 {
|
return ret, err, rt
|
||||||
ret, err := vm.Invoke(toActor, rt, msg.Method, msg.Params)
|
|
||||||
return ret, err, rt
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil, rt
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkMessage(msg *types.Message) error {
|
func checkMessage(msg *types.Message) error {
|
||||||
@@ -243,17 +278,18 @@ func checkMessage(msg *types.Message) error {
|
|||||||
|
|
||||||
func (vm *VM) ApplyImplicitMessage(ctx context.Context, msg *types.Message) (*ApplyRet, error) {
|
func (vm *VM) ApplyImplicitMessage(ctx context.Context, msg *types.Message) (*ApplyRet, error) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
ret, actorErr, rt := vm.send(ctx, msg, nil, 0)
|
ret, actorErr, rt := vm.send(ctx, msg, nil, nil, start)
|
||||||
|
rt.finilizeGasTracing()
|
||||||
return &ApplyRet{
|
return &ApplyRet{
|
||||||
MessageReceipt: types.MessageReceipt{
|
MessageReceipt: types.MessageReceipt{
|
||||||
ExitCode: aerrors.RetCode(actorErr),
|
ExitCode: aerrors.RetCode(actorErr),
|
||||||
Return: ret,
|
Return: ret,
|
||||||
GasUsed: 0,
|
GasUsed: 0,
|
||||||
},
|
},
|
||||||
ActorErr: actorErr,
|
ActorErr: actorErr,
|
||||||
InternalExecutions: rt.internalExecutions,
|
ExecutionTrace: rt.executionTrace,
|
||||||
Penalty: types.NewInt(0),
|
Penalty: types.NewInt(0),
|
||||||
Duration: time.Since(start),
|
Duration: time.Since(start),
|
||||||
}, actorErr
|
}, actorErr
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,7 +312,8 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
|
|||||||
|
|
||||||
pl := PricelistByEpoch(vm.blockHeight)
|
pl := PricelistByEpoch(vm.blockHeight)
|
||||||
|
|
||||||
msgGasCost := pl.OnChainMessage(cmsg.ChainLength())
|
msgGas := pl.OnChainMessage(cmsg.ChainLength())
|
||||||
|
msgGasCost := msgGas.Total()
|
||||||
// this should never happen, but is currently still exercised by some tests
|
// this should never happen, but is currently still exercised by some tests
|
||||||
if msgGasCost > msg.GasLimit {
|
if msgGasCost > msg.GasLimit {
|
||||||
return &ApplyRet{
|
return &ApplyRet{
|
||||||
@@ -359,7 +396,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
|
|||||||
}
|
}
|
||||||
defer st.ClearSnapshot()
|
defer st.ClearSnapshot()
|
||||||
|
|
||||||
ret, actorErr, rt := vm.send(ctx, msg, nil, msgGasCost)
|
ret, actorErr, rt := vm.send(ctx, msg, nil, &msgGas, start)
|
||||||
if aerrors.IsFatal(actorErr) {
|
if aerrors.IsFatal(actorErr) {
|
||||||
return nil, xerrors.Errorf("[from=%s,to=%s,n=%d,m=%d,h=%d] fatal error: %w", msg.From, msg.To, msg.Nonce, msg.Method, vm.blockHeight, actorErr)
|
return nil, xerrors.Errorf("[from=%s,to=%s,n=%d,m=%d,h=%d] fatal error: %w", msg.From, msg.To, msg.Nonce, msg.Method, vm.blockHeight, actorErr)
|
||||||
}
|
}
|
||||||
@@ -413,16 +450,18 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
|
|||||||
return nil, xerrors.Errorf("gas handling math is wrong")
|
return nil, xerrors.Errorf("gas handling math is wrong")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rt.finilizeGasTracing()
|
||||||
|
|
||||||
return &ApplyRet{
|
return &ApplyRet{
|
||||||
MessageReceipt: types.MessageReceipt{
|
MessageReceipt: types.MessageReceipt{
|
||||||
ExitCode: errcode,
|
ExitCode: errcode,
|
||||||
Return: ret,
|
Return: ret,
|
||||||
GasUsed: gasUsed,
|
GasUsed: gasUsed,
|
||||||
},
|
},
|
||||||
ActorErr: actorErr,
|
ActorErr: actorErr,
|
||||||
InternalExecutions: rt.internalExecutions,
|
ExecutionTrace: rt.executionTrace,
|
||||||
Penalty: types.NewInt(0),
|
Penalty: types.NewInt(0),
|
||||||
Duration: time.Since(start),
|
Duration: time.Since(start),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -454,7 +493,7 @@ func (vm *VM) Flush(ctx context.Context) (cid.Cid, error) {
|
|||||||
return root, nil
|
return root, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// vm.MutateState(idAddr, func(cst cbor.IpldStore, st *ActorStateType) error {...})
|
// MutateState usage: MutateState(ctx, idAddr, func(cst cbor.IpldStore, st *ActorStateType) error {...})
|
||||||
func (vm *VM) MutateState(ctx context.Context, addr address.Address, fn interface{}) error {
|
func (vm *VM) MutateState(ctx context.Context, addr address.Address, fn interface{}) error {
|
||||||
act, err := vm.cstate.GetActor(addr)
|
act, err := vm.cstate.GetActor(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -591,7 +630,7 @@ func (vm *VM) Invoke(act *types.Actor, rt *Runtime, method abi.MethodNum, params
|
|||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vm *VM) SetInvoker(i *invoker) {
|
func (vm *VM) SetInvoker(i *Invoker) {
|
||||||
vm.inv = i
|
vm.inv = i
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -607,17 +646,17 @@ func (vm *VM) transfer(from, to address.Address, amt types.BigInt) aerrors.Actor
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
fromId, err := vm.cstate.LookupID(from)
|
fromID, err := vm.cstate.LookupID(from)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return aerrors.Fatalf("transfer failed when resolving sender address: %s", err)
|
return aerrors.Fatalf("transfer failed when resolving sender address: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
toId, err := vm.cstate.LookupID(to)
|
toID, err := vm.cstate.LookupID(to)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return aerrors.Fatalf("transfer failed when resolving receiver address: %s", err)
|
return aerrors.Fatalf("transfer failed when resolving receiver address: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if fromId == toId {
|
if fromID == toID {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -625,12 +664,12 @@ func (vm *VM) transfer(from, to address.Address, amt types.BigInt) aerrors.Actor
|
|||||||
return aerrors.Newf(exitcode.SysErrForbidden, "attempted to transfer negative value: %s", amt)
|
return aerrors.Newf(exitcode.SysErrForbidden, "attempted to transfer negative value: %s", amt)
|
||||||
}
|
}
|
||||||
|
|
||||||
f, err := vm.cstate.GetActor(fromId)
|
f, err := vm.cstate.GetActor(fromID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return aerrors.Fatalf("transfer failed when retrieving sender actor: %s", err)
|
return aerrors.Fatalf("transfer failed when retrieving sender actor: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
t, err := vm.cstate.GetActor(toId)
|
t, err := vm.cstate.GetActor(toID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return aerrors.Fatalf("transfer failed when retrieving receiver actor: %s", err)
|
return aerrors.Fatalf("transfer failed when retrieving receiver actor: %s", err)
|
||||||
}
|
}
|
||||||
@@ -640,11 +679,11 @@ func (vm *VM) transfer(from, to address.Address, amt types.BigInt) aerrors.Actor
|
|||||||
}
|
}
|
||||||
depositFunds(t, amt)
|
depositFunds(t, amt)
|
||||||
|
|
||||||
if err := vm.cstate.SetActor(fromId, f); err != nil {
|
if err := vm.cstate.SetActor(fromID, f); err != nil {
|
||||||
return aerrors.Fatalf("transfer failed when setting receiver actor: %s", err)
|
return aerrors.Fatalf("transfer failed when setting receiver actor: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := vm.cstate.SetActor(toId, t); err != nil {
|
if err := vm.cstate.SetActor(toID, t); err != nil {
|
||||||
return aerrors.Fatalf("transfer failed when setting sender actor: %s", err)
|
return aerrors.Fatalf("transfer failed when setting sender actor: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+22
-4
@@ -22,10 +22,11 @@ import (
|
|||||||
var log = logging.Logger("wallet")
|
var log = logging.Logger("wallet")
|
||||||
|
|
||||||
const (
|
const (
|
||||||
KNamePrefix = "wallet-"
|
KNamePrefix = "wallet-"
|
||||||
KDefault = "default"
|
KTrashPrefix = "trash-"
|
||||||
KTBLS = "bls"
|
KDefault = "default"
|
||||||
KTSecp256k1 = "secp256k1"
|
KTBLS = "bls"
|
||||||
|
KTSecp256k1 = "secp256k1"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Wallet struct {
|
type Wallet struct {
|
||||||
@@ -230,6 +231,23 @@ func (w *Wallet) HasKey(addr address.Address) (bool, error) {
|
|||||||
return k != nil, nil
|
return k != nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *Wallet) DeleteKey(addr address.Address) error {
|
||||||
|
k, err := w.findKey(addr)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("failed to delete key %s : %w", addr, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := w.keystore.Put(KTrashPrefix+k.Address.String(), k.KeyInfo); err != nil {
|
||||||
|
return xerrors.Errorf("failed to mark key %s as trashed: %w", addr, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := w.keystore.Delete(KNamePrefix + k.Address.String()); err != nil {
|
||||||
|
return xerrors.Errorf("failed to delete key %s: %w", addr, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type Key struct {
|
type Key struct {
|
||||||
types.KeyInfo
|
types.KeyInfo
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -3,8 +3,8 @@ package cli
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
"gopkg.in/urfave/cli.v2"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-jsonrpc/auth"
|
"github.com/filecoin-project/go-jsonrpc/auth"
|
||||||
|
|
||||||
|
|||||||
+38
-7
@@ -12,7 +12,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/go-units"
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
cborutil "github.com/filecoin-project/go-cbor-util"
|
cborutil "github.com/filecoin-project/go-cbor-util"
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||||
@@ -23,9 +22,9 @@ import (
|
|||||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||||
cid "github.com/ipfs/go-cid"
|
cid "github.com/ipfs/go-cid"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
"gopkg.in/urfave/cli.v2"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/chain/actors"
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
@@ -222,6 +221,9 @@ var chainStatObjCmd = &cli.Command{
|
|||||||
base := cid.Undef
|
base := cid.Undef
|
||||||
if cctx.IsSet("base") {
|
if cctx.IsSet("base") {
|
||||||
base, err = cid.Decode(cctx.String("base"))
|
base, err = cid.Decode(cctx.String("base"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stats, err := api.ChainStatObj(ctx, obj, base)
|
stats, err := api.ChainStatObj(ctx, obj, base)
|
||||||
@@ -230,7 +232,7 @@ var chainStatObjCmd = &cli.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Links: %d\n", stats.Links)
|
fmt.Printf("Links: %d\n", stats.Links)
|
||||||
fmt.Printf("Size: %s (%d)\n", units.BytesSize(float64(stats.Size)), stats.Size)
|
fmt.Printf("Size: %s (%d)\n", types.SizeStr(types.NewInt(stats.Size)), stats.Size)
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -442,7 +444,8 @@ var chainGetCmd = &cli.Command{
|
|||||||
- /ipfs/[cid]/@Hi:123 - get varint elem 123 from hamt
|
- /ipfs/[cid]/@Hi:123 - get varint elem 123 from hamt
|
||||||
- /ipfs/[cid]/@Hu:123 - get uvarint elem 123 from hamt
|
- /ipfs/[cid]/@Hu:123 - get uvarint elem 123 from hamt
|
||||||
- /ipfs/[cid]/@Ha:t01 - get element under Addr(t01).Bytes
|
- /ipfs/[cid]/@Ha:t01 - get element under Addr(t01).Bytes
|
||||||
- /ipfs/[cid]/@A:10 - get 10th amt element
|
- /ipfs/[cid]/@A:10 - get 10th amt element
|
||||||
|
- .../@Ha:t01/@state - get pretty map-based actor state
|
||||||
|
|
||||||
List of --as-type types:
|
List of --as-type types:
|
||||||
- raw
|
- raw
|
||||||
@@ -841,6 +844,10 @@ var slashConsensusFault = &cli.Command{
|
|||||||
Name: "miner",
|
Name: "miner",
|
||||||
Usage: "Miner address",
|
Usage: "Miner address",
|
||||||
},
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "extra",
|
||||||
|
Usage: "Extra block cid",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
api, closer, err := GetFullNodeAPI(cctx)
|
api, closer, err := GetFullNodeAPI(cctx)
|
||||||
@@ -885,10 +892,34 @@ var slashConsensusFault = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
params, err := actors.SerializeParams(&miner.ReportConsensusFaultParams{
|
params := miner.ReportConsensusFaultParams{
|
||||||
BlockHeader1: bh1,
|
BlockHeader1: bh1,
|
||||||
BlockHeader2: bh2,
|
BlockHeader2: bh2,
|
||||||
})
|
}
|
||||||
|
|
||||||
|
if cctx.String("extra") != "" {
|
||||||
|
cExtra, err := cid.Parse(cctx.String("extra"))
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("parsing cid extra: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bExtra, err := api.ChainGetBlock(ctx, cExtra)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("getting block extra: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
be, err := cborutil.Dump(bExtra)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
params.BlockHeaderExtra = be
|
||||||
|
}
|
||||||
|
|
||||||
|
enc, err := actors.SerializeParams(¶ms)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if cctx.String("miner") == "" {
|
if cctx.String("miner") == "" {
|
||||||
return xerrors.Errorf("--miner flag is required")
|
return xerrors.Errorf("--miner flag is required")
|
||||||
@@ -906,7 +937,7 @@ var slashConsensusFault = &cli.Command{
|
|||||||
GasPrice: types.NewInt(1),
|
GasPrice: types.NewInt(1),
|
||||||
GasLimit: 10000000,
|
GasLimit: 10000000,
|
||||||
Method: builtin.MethodsMiner.ReportConsensusFault,
|
Method: builtin.MethodsMiner.ReportConsensusFault,
|
||||||
Params: params,
|
Params: enc,
|
||||||
}
|
}
|
||||||
|
|
||||||
smsg, err := api.MpoolPushMessage(ctx, msg)
|
smsg, err := api.MpoolPushMessage(ctx, msg)
|
||||||
|
|||||||
+105
-24
@@ -8,19 +8,48 @@ import (
|
|||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
|
"github.com/ipfs/go-cidutil/cidenc"
|
||||||
"github.com/libp2p/go-libp2p-core/peer"
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
|
"github.com/multiformats/go-multibase"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
"gopkg.in/urfave/cli.v2"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/market"
|
"github.com/filecoin-project/specs-actors/actors/builtin/market"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/api"
|
||||||
lapi "github.com/filecoin-project/lotus/api"
|
lapi "github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var CidBaseFlag = cli.StringFlag{
|
||||||
|
Name: "cid-base",
|
||||||
|
Hidden: true,
|
||||||
|
Value: "base32",
|
||||||
|
Usage: "Multibase encoding used for version 1 CIDs in output.",
|
||||||
|
DefaultText: "base32",
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCidEncoder returns an encoder using the `cid-base` flag if provided, or
|
||||||
|
// the default (Base32) encoder if not.
|
||||||
|
func GetCidEncoder(cctx *cli.Context) (cidenc.Encoder, error) {
|
||||||
|
val := cctx.String("cid-base")
|
||||||
|
|
||||||
|
e := cidenc.Encoder{Base: multibase.MustNewEncoder(multibase.Base32)}
|
||||||
|
|
||||||
|
if val != "" {
|
||||||
|
var err error
|
||||||
|
e.Base, err = multibase.EncoderByName(val)
|
||||||
|
if err != nil {
|
||||||
|
return e, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return e, nil
|
||||||
|
}
|
||||||
|
|
||||||
var clientCmd = &cli.Command{
|
var clientCmd = &cli.Command{
|
||||||
Name: "client",
|
Name: "client",
|
||||||
Usage: "Make deals, store data, retrieve data",
|
Usage: "Make deals, store data, retrieve data",
|
||||||
@@ -46,6 +75,7 @@ var clientImportCmd = &cli.Command{
|
|||||||
Name: "car",
|
Name: "car",
|
||||||
Usage: "import from a car file instead of a regular file",
|
Usage: "import from a car file instead of a regular file",
|
||||||
},
|
},
|
||||||
|
&CidBaseFlag,
|
||||||
},
|
},
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
api, closer, err := GetFullNodeAPI(cctx)
|
api, closer, err := GetFullNodeAPI(cctx)
|
||||||
@@ -67,7 +97,14 @@ var clientImportCmd = &cli.Command{
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Println(c.String())
|
|
||||||
|
encoder, err := GetCidEncoder(cctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(encoder.Encode(c))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -76,6 +113,9 @@ var clientCommPCmd = &cli.Command{
|
|||||||
Name: "commP",
|
Name: "commP",
|
||||||
Usage: "calculate the piece-cid (commP) of a CAR file",
|
Usage: "calculate the piece-cid (commP) of a CAR file",
|
||||||
ArgsUsage: "[inputFile minerAddress]",
|
ArgsUsage: "[inputFile minerAddress]",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&CidBaseFlag,
|
||||||
|
},
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
api, closer, err := GetFullNodeAPI(cctx)
|
api, closer, err := GetFullNodeAPI(cctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -94,12 +134,17 @@ var clientCommPCmd = &cli.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret, err := api.ClientCalcCommP(ctx, cctx.Args().Get(0), miner)
|
ret, err := api.ClientCalcCommP(ctx, cctx.Args().Get(0), miner)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Println("CID: ", ret.Root)
|
|
||||||
fmt.Println("Piece size: ", ret.Size)
|
encoder, err := GetCidEncoder(cctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("CID: ", encoder.Encode(ret.Root))
|
||||||
|
fmt.Println("Piece size: ", types.SizeStr(types.NewInt(uint64(ret.Size))))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -137,6 +182,9 @@ var clientCarGenCmd = &cli.Command{
|
|||||||
var clientLocalCmd = &cli.Command{
|
var clientLocalCmd = &cli.Command{
|
||||||
Name: "local",
|
Name: "local",
|
||||||
Usage: "List locally imported data",
|
Usage: "List locally imported data",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&CidBaseFlag,
|
||||||
|
},
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
api, closer, err := GetFullNodeAPI(cctx)
|
api, closer, err := GetFullNodeAPI(cctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -149,8 +197,14 @@ var clientLocalCmd = &cli.Command{
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
encoder, err := GetCidEncoder(cctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
for _, v := range list {
|
for _, v := range list {
|
||||||
fmt.Printf("%s %s %d %s\n", v.Key, v.FilePath, v.Size, v.Status)
|
fmt.Printf("%s %s %s %s\n", encoder.Encode(v.Key), v.FilePath, types.SizeStr(types.NewInt(v.Size)), v.Status)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
@@ -178,6 +232,7 @@ var clientDealCmd = &cli.Command{
|
|||||||
Usage: "specify the epoch that the deal should start at",
|
Usage: "specify the epoch that the deal should start at",
|
||||||
Value: -1,
|
Value: -1,
|
||||||
},
|
},
|
||||||
|
&CidBaseFlag,
|
||||||
},
|
},
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
api, closer, err := GetFullNodeAPI(cctx)
|
api, closer, err := GetFullNodeAPI(cctx)
|
||||||
@@ -263,7 +318,13 @@ var clientDealCmd = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(proposal)
|
encoder, err := GetCidEncoder(cctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(encoder.Encode(*proposal))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -311,7 +372,7 @@ var clientFindCmd = &cli.Command{
|
|||||||
fmt.Printf("ERR %s@%s: %s\n", offer.Miner, offer.MinerPeerID, offer.Err)
|
fmt.Printf("ERR %s@%s: %s\n", offer.Miner, offer.MinerPeerID, offer.Err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fmt.Printf("RETRIEVAL %s@%s-%sfil-%db\n", offer.Miner, offer.MinerPeerID, types.FIL(offer.MinPrice), offer.Size)
|
fmt.Printf("RETRIEVAL %s@%s-%sfil-%s\n", offer.Miner, offer.MinerPeerID, types.FIL(offer.MinPrice), types.SizeStr(types.NewInt(offer.Size)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -331,6 +392,10 @@ var clientRetrieveCmd = &cli.Command{
|
|||||||
Name: "car",
|
Name: "car",
|
||||||
Usage: "export to a car file instead of a regular file",
|
Usage: "export to a car file instead of a regular file",
|
||||||
},
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "miner",
|
||||||
|
Usage: "miner address for retrieval, if not present it'll use local discovery",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
if cctx.NArg() != 2 {
|
if cctx.NArg() != 2 {
|
||||||
@@ -338,7 +403,7 @@ var clientRetrieveCmd = &cli.Command{
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
api, closer, err := GetFullNodeAPI(cctx)
|
fapi, closer, err := GetFullNodeAPI(cctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -349,7 +414,7 @@ var clientRetrieveCmd = &cli.Command{
|
|||||||
if cctx.String("address") != "" {
|
if cctx.String("address") != "" {
|
||||||
payer, err = address.NewFromString(cctx.String("address"))
|
payer, err = address.NewFromString(cctx.String("address"))
|
||||||
} else {
|
} else {
|
||||||
payer, err = api.WalletDefaultAddress(ctx)
|
payer, err = fapi.WalletDefaultAddress(ctx)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -372,23 +437,39 @@ var clientRetrieveCmd = &cli.Command{
|
|||||||
return nil
|
return nil
|
||||||
}*/ // TODO: fix
|
}*/ // TODO: fix
|
||||||
|
|
||||||
offers, err := api.ClientFindData(ctx, file)
|
var offer api.QueryOffer
|
||||||
if err != nil {
|
minerStrAddr := cctx.String("miner")
|
||||||
return err
|
if minerStrAddr == "" { // Local discovery
|
||||||
|
offers, err := fapi.ClientFindData(ctx, file)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: parse offer strings from `client find`, make this smarter
|
||||||
|
if len(offers) < 1 {
|
||||||
|
fmt.Println("Failed to find file")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
offer = offers[0]
|
||||||
|
} else { // Directed retrieval
|
||||||
|
minerAddr, err := address.NewFromString(minerStrAddr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
offer, err = fapi.ClientMinerQueryOffer(ctx, file, minerAddr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if offer.Err != "" {
|
||||||
// TODO: parse offer strings from `client find`, make this smarter
|
return fmt.Errorf("The received offer errored: %s", offer.Err)
|
||||||
|
|
||||||
if len(offers) < 1 {
|
|
||||||
fmt.Println("Failed to find file")
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ref := &lapi.FileRef{
|
ref := &lapi.FileRef{
|
||||||
Path: cctx.Args().Get(1),
|
Path: cctx.Args().Get(1),
|
||||||
IsCAR: cctx.Bool("car"),
|
IsCAR: cctx.Bool("car"),
|
||||||
}
|
}
|
||||||
if err := api.ClientRetrieve(ctx, offers[0].Order(payer), ref); err != nil {
|
if err := fapi.ClientRetrieve(ctx, offer.Order(payer), ref); err != nil {
|
||||||
return xerrors.Errorf("Retrieval Failed: %w", err)
|
return xerrors.Errorf("Retrieval Failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -446,11 +527,11 @@ var clientQueryAskCmd = &cli.Command{
|
|||||||
return xerrors.Errorf("failed to get peerID for miner: %w", err)
|
return xerrors.Errorf("failed to get peerID for miner: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if mi.PeerId == peer.ID("SETME") {
|
if peer.ID(mi.PeerId) == peer.ID("SETME") {
|
||||||
return fmt.Errorf("the miner hasn't initialized yet")
|
return fmt.Errorf("the miner hasn't initialized yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
pid = mi.PeerId
|
pid = peer.ID(mi.PeerId)
|
||||||
}
|
}
|
||||||
|
|
||||||
ask, err := api.ClientQueryAsk(ctx, pid, maddr)
|
ask, err := api.ClientQueryAsk(ctx, pid, maddr)
|
||||||
@@ -460,7 +541,7 @@ var clientQueryAskCmd = &cli.Command{
|
|||||||
|
|
||||||
fmt.Printf("Ask: %s\n", maddr)
|
fmt.Printf("Ask: %s\n", maddr)
|
||||||
fmt.Printf("Price per GiB: %s\n", types.FIL(ask.Ask.Price))
|
fmt.Printf("Price per GiB: %s\n", types.FIL(ask.Ask.Price))
|
||||||
fmt.Printf("Max Piece size: %d\n", ask.Ask.MaxPieceSize)
|
fmt.Printf("Max Piece size: %s\n", types.SizeStr(types.NewInt(uint64(ask.Ask.MaxPieceSize))))
|
||||||
|
|
||||||
size := cctx.Int64("size")
|
size := cctx.Int64("size")
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
@@ -537,7 +618,7 @@ var clientListDeals = &cli.Command{
|
|||||||
slashed = fmt.Sprintf("Y (epoch %d)", d.OnChainDealState.SlashEpoch)
|
slashed = fmt.Sprintf("Y (epoch %d)", d.OnChainDealState.SlashEpoch)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(w, "%s\t%d\t%s\t%s\t%s\t%s\t%s\t%d\t%s\t%d\t%s\n", d.LocalDeal.ProposalCid, d.LocalDeal.DealID, d.LocalDeal.Provider, storagemarket.DealStates[d.LocalDeal.State], onChain, slashed, d.LocalDeal.PieceCID, d.LocalDeal.Size, d.LocalDeal.PricePerEpoch, d.LocalDeal.Duration, d.LocalDeal.Message)
|
fmt.Fprintf(w, "%s\t%d\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%d\t%s\n", d.LocalDeal.ProposalCid, d.LocalDeal.DealID, d.LocalDeal.Provider, storagemarket.DealStates[d.LocalDeal.State], onChain, slashed, d.LocalDeal.PieceCID, types.SizeStr(types.NewInt(d.LocalDeal.Size)), d.LocalDeal.PricePerEpoch, d.LocalDeal.Duration, d.LocalDeal.Message)
|
||||||
}
|
}
|
||||||
return w.Flush()
|
return w.Flush()
|
||||||
},
|
},
|
||||||
|
|||||||
+1
-1
@@ -13,8 +13,8 @@ import (
|
|||||||
"github.com/mitchellh/go-homedir"
|
"github.com/mitchellh/go-homedir"
|
||||||
"github.com/multiformats/go-multiaddr"
|
"github.com/multiformats/go-multiaddr"
|
||||||
manet "github.com/multiformats/go-multiaddr-net"
|
manet "github.com/multiformats/go-multiaddr-net"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
"gopkg.in/urfave/cli.v2"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-jsonrpc"
|
"github.com/filecoin-project/go-jsonrpc"
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -3,8 +3,8 @@ package cli
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
"gopkg.in/urfave/cli.v2"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var logCmd = &cli.Command{
|
var logCmd = &cli.Command{
|
||||||
|
|||||||
+1
-1
@@ -5,8 +5,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
"gopkg.in/urfave/cli.v2"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
|
|
||||||
|
|||||||
+5
-4
@@ -17,12 +17,13 @@ import (
|
|||||||
cid "github.com/ipfs/go-cid"
|
cid "github.com/ipfs/go-cid"
|
||||||
"github.com/ipfs/go-hamt-ipld"
|
"github.com/ipfs/go-hamt-ipld"
|
||||||
cbor "github.com/ipfs/go-ipld-cbor"
|
cbor "github.com/ipfs/go-ipld-cbor"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
"gopkg.in/urfave/cli.v2"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/api/apibstore"
|
"github.com/filecoin-project/lotus/api/apibstore"
|
||||||
|
"github.com/filecoin-project/lotus/build"
|
||||||
types "github.com/filecoin-project/lotus/chain/types"
|
types "github.com/filecoin-project/lotus/chain/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -117,7 +118,7 @@ var msigCreateCmd = &cli.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
// wait for it to get mined into a block
|
// wait for it to get mined into a block
|
||||||
wait, err := api.StateWaitMsg(ctx, msgCid)
|
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -336,7 +337,7 @@ var msigProposeCmd = &cli.Command{
|
|||||||
|
|
||||||
fmt.Println("send proposal in message: ", msgCid)
|
fmt.Println("send proposal in message: ", msgCid)
|
||||||
|
|
||||||
wait, err := api.StateWaitMsg(ctx, msgCid)
|
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -452,7 +453,7 @@ var msigApproveCmd = &cli.Command{
|
|||||||
|
|
||||||
fmt.Println("sent approval in message: ", msgCid)
|
fmt.Println("sent approval in message: ", msgCid)
|
||||||
|
|
||||||
wait, err := api.StateWaitMsg(ctx, msgCid)
|
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-2
@@ -7,7 +7,7 @@ import (
|
|||||||
|
|
||||||
"github.com/libp2p/go-libp2p-core/peer"
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
|
|
||||||
"gopkg.in/urfave/cli.v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/lib/addrutil"
|
"github.com/filecoin-project/lotus/lib/addrutil"
|
||||||
)
|
)
|
||||||
@@ -21,6 +21,7 @@ var netCmd = &cli.Command{
|
|||||||
netListen,
|
netListen,
|
||||||
netId,
|
netId,
|
||||||
netFindPeer,
|
netFindPeer,
|
||||||
|
netScores,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +45,30 @@ var netPeers = &cli.Command{
|
|||||||
})
|
})
|
||||||
|
|
||||||
for _, peer := range peers {
|
for _, peer := range peers {
|
||||||
fmt.Println(peer)
|
fmt.Printf("%s, %s\n", peer.ID, peer.Addrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var netScores = &cli.Command{
|
||||||
|
Name: "scores",
|
||||||
|
Usage: "Print peers' pubsub scores",
|
||||||
|
Action: func(cctx *cli.Context) error {
|
||||||
|
api, closer, err := GetAPI(cctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer closer()
|
||||||
|
ctx := ReqContext(cctx)
|
||||||
|
scores, err := api.NetPubsubScores(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, peer := range scores {
|
||||||
|
fmt.Printf("%s, %f\n", peer.ID, peer.Score)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
+11
-12
@@ -3,28 +3,27 @@ package cli
|
|||||||
import (
|
import (
|
||||||
"github.com/docker/go-units"
|
"github.com/docker/go-units"
|
||||||
paramfetch "github.com/filecoin-project/go-paramfetch"
|
paramfetch "github.com/filecoin-project/go-paramfetch"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
"gopkg.in/urfave/cli.v2"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
)
|
)
|
||||||
|
|
||||||
var fetchParamCmd = &cli.Command{
|
var fetchParamCmd = &cli.Command{
|
||||||
Name: "fetch-params",
|
Name: "fetch-params",
|
||||||
Usage: "Fetch proving parameters",
|
Usage: "Fetch proving parameters",
|
||||||
Flags: []cli.Flag{
|
ArgsUsage: "[sectorSize]",
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "proving-params",
|
|
||||||
Usage: "download params used creating proofs for given size, i.e. 32GiB",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
sectorSizeInt, err := units.RAMInBytes(cctx.String("proving-params"))
|
if !cctx.Args().Present() {
|
||||||
|
return xerrors.Errorf("must pass sector size to fetch params for (specify as \"32GiB\", for instance)")
|
||||||
|
}
|
||||||
|
sectorSizeInt, err := units.RAMInBytes(cctx.Args().First())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return xerrors.Errorf("error parsing sector size (specify as \"32GiB\", for instance): %w", err)
|
||||||
}
|
}
|
||||||
sectorSize := uint64(sectorSizeInt)
|
sectorSize := uint64(sectorSizeInt)
|
||||||
err = paramfetch.GetParams(build.ParametersJSON(), sectorSize)
|
|
||||||
|
err = paramfetch.GetParams(ReqContext(cctx), build.ParametersJSON(), sectorSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("fetching proof parameters: %w", err)
|
return xerrors.Errorf("fetching proof parameters: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -4,10 +4,11 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/filecoin-project/lotus/build"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||||
"gopkg.in/urfave/cli.v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
types "github.com/filecoin-project/lotus/chain/types"
|
types "github.com/filecoin-project/lotus/chain/types"
|
||||||
)
|
)
|
||||||
@@ -361,7 +362,7 @@ var paychVoucherSubmitCmd = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
mwait, err := api.StateWaitMsg(ctx, mcid)
|
mwait, err := api.StateWaitMsg(ctx, mcid, build.MessageConfidence)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"gopkg.in/urfave/cli.v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var sendCmd = &cli.Command{
|
var sendCmd = &cli.Command{
|
||||||
|
|||||||
+259
-141
@@ -5,19 +5,20 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"html/template"
|
||||||
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/go-units"
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
"github.com/libp2p/go-libp2p-core/peer"
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
"github.com/multiformats/go-multihash"
|
"github.com/multiformats/go-multihash"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
"gopkg.in/urfave/cli.v2"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||||
@@ -32,15 +33,17 @@ import (
|
|||||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
"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/reward"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
||||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/miner"
|
"github.com/filecoin-project/lotus/miner"
|
||||||
)
|
)
|
||||||
|
|
||||||
type methodMeta struct {
|
type methodMeta struct {
|
||||||
name string
|
Name string
|
||||||
|
|
||||||
params reflect.Type
|
params reflect.Type
|
||||||
ret reflect.Type
|
ret reflect.Type
|
||||||
@@ -68,7 +71,7 @@ func init() {
|
|||||||
nf := rt.NumField()
|
nf := rt.NumField()
|
||||||
|
|
||||||
methods[c] = append(methods[c], methodMeta{
|
methods[c] = append(methods[c], methodMeta{
|
||||||
name: "Send",
|
Name: "Send",
|
||||||
params: reflect.TypeOf(new(adt.EmptyValue)),
|
params: reflect.TypeOf(new(adt.EmptyValue)),
|
||||||
ret: reflect.TypeOf(new(adt.EmptyValue)),
|
ret: reflect.TypeOf(new(adt.EmptyValue)),
|
||||||
})
|
})
|
||||||
@@ -78,7 +81,7 @@ func init() {
|
|||||||
export := reflect.TypeOf(exports[i+1])
|
export := reflect.TypeOf(exports[i+1])
|
||||||
|
|
||||||
methods[c] = append(methods[c], methodMeta{
|
methods[c] = append(methods[c], methodMeta{
|
||||||
name: rt.Field(i).Name,
|
Name: rt.Field(i).Name,
|
||||||
params: export.In(1),
|
params: export.In(1),
|
||||||
ret: export.Out(0),
|
ret: export.Out(0),
|
||||||
})
|
})
|
||||||
@@ -144,27 +147,15 @@ var stateMinerInfo = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
act, err := api.StateGetActor(ctx, addr, ts.Key())
|
mi, err := api.StateMinerInfo(ctx, addr, ts.Key())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
aso, err := api.ChainReadObj(ctx, act.Head)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var mst miner2.State
|
|
||||||
if err := mst.UnmarshalCBOR(bytes.NewReader(aso)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
mi := mst.Info
|
|
||||||
|
|
||||||
fmt.Printf("Owner:\t%s\n", mi.Owner)
|
fmt.Printf("Owner:\t%s\n", mi.Owner)
|
||||||
fmt.Printf("Worker:\t%s\n", mi.Worker)
|
fmt.Printf("Worker:\t%s\n", mi.Worker)
|
||||||
fmt.Printf("PeerID:\t%s\n", mi.PeerId)
|
fmt.Printf("PeerID:\t%s\n", mi.PeerId)
|
||||||
fmt.Printf("SectorSize:\t%s (%d)\n", units.BytesSize(float64(mi.SectorSize)), mi.SectorSize)
|
fmt.Printf("SectorSize:\t%s (%d)\n", types.SizeStr(types.NewInt(uint64(mi.SectorSize))), mi.SectorSize)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
@@ -360,7 +351,7 @@ var stateReplaySetCmd = &cli.Command{
|
|||||||
return fmt.Errorf("message cid was invalid: %s", err)
|
return fmt.Errorf("message cid was invalid: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
api, closer, err := GetFullNodeAPI(cctx)
|
fapi, closer, err := GetFullNodeAPI(cctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -382,7 +373,7 @@ var stateReplaySetCmd = &cli.Command{
|
|||||||
if len(tscids) > 0 {
|
if len(tscids) > 0 {
|
||||||
var headers []*types.BlockHeader
|
var headers []*types.BlockHeader
|
||||||
for _, c := range tscids {
|
for _, c := range tscids {
|
||||||
h, err := api.ChainGetBlock(ctx, c)
|
h, err := fapi.ChainGetBlock(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -392,12 +383,13 @@ var stateReplaySetCmd = &cli.Command{
|
|||||||
|
|
||||||
ts, err = types.NewTipSet(headers)
|
ts, err = types.NewTipSet(headers)
|
||||||
} else {
|
} else {
|
||||||
r, err := api.StateWaitMsg(ctx, mcid)
|
var r *api.MsgLookup
|
||||||
|
r, err = fapi.StateWaitMsg(ctx, mcid, build.MessageConfidence)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("finding message in chain: %w", err)
|
return xerrors.Errorf("finding message in chain: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ts, err = api.ChainGetTipSet(ctx, r.TipSet.Parents())
|
ts, err = fapi.ChainGetTipSet(ctx, r.TipSet.Parents())
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -405,7 +397,7 @@ var stateReplaySetCmd = &cli.Command{
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := api.StateReplay(ctx, ts.Key(), mcid)
|
res, err := fapi.StateReplay(ctx, ts.Key(), mcid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("replay call failed: %w", err)
|
return xerrors.Errorf("replay call failed: %w", err)
|
||||||
}
|
}
|
||||||
@@ -718,7 +710,7 @@ var stateSectorSizeCmd = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("%d\n", mi.SectorSize)
|
fmt.Printf("%s (%d)\n", types.SizeStr(types.NewInt(uint64(mi.SectorSize))), mi.SectorSize)
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -750,12 +742,7 @@ var stateReadStateCmd = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
act, err := api.StateGetActor(ctx, addr, ts.Key())
|
as, err := api.StateReadState(ctx, addr, ts.Key())
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
as, err := api.StateReadState(ctx, act, ts.Key())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -935,37 +922,29 @@ var stateComputeStateCmd = &cli.Command{
|
|||||||
return c.Code, nil
|
return c.Code, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return computeStateHtml(ts, stout, getCode)
|
return computeStateHTMLTempl(ts, stout, getCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("computed state cid: ", stout.Root)
|
fmt.Println("computed state cid: ", stout.Root)
|
||||||
if cctx.Bool("show-trace") {
|
if cctx.Bool("show-trace") {
|
||||||
for _, ir := range stout.Trace {
|
for _, ir := range stout.Trace {
|
||||||
fmt.Printf("%s\t%s\t%s\t%d\t%x\t%d\t%x\n", ir.Msg.From, ir.Msg.To, ir.Msg.Value, ir.Msg.Method, ir.Msg.Params, ir.MsgRct.ExitCode, ir.MsgRct.Return)
|
fmt.Printf("%s\t%s\t%s\t%d\t%x\t%d\t%x\n", ir.Msg.From, ir.Msg.To, ir.Msg.Value, ir.Msg.Method, ir.Msg.Params, ir.MsgRct.ExitCode, ir.MsgRct.Return)
|
||||||
printInternalExecutions("\t", ir.InternalExecutions)
|
printInternalExecutions("\t", ir.ExecutionTrace.Subcalls)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func printInternalExecutions(prefix string, trace []*types.ExecutionResult) {
|
func printInternalExecutions(prefix string, trace []types.ExecutionTrace) {
|
||||||
for _, im := range trace {
|
for _, im := range trace {
|
||||||
fmt.Printf("%s%s\t%s\t%s\t%d\t%x\t%d\t%x\n", prefix, im.Msg.From, im.Msg.To, im.Msg.Value, im.Msg.Method, im.Msg.Params, im.MsgRct.ExitCode, im.MsgRct.Return)
|
fmt.Printf("%s%s\t%s\t%s\t%d\t%x\t%d\t%x\n", prefix, im.Msg.From, im.Msg.To, im.Msg.Value, im.Msg.Method, im.Msg.Params, im.MsgRct.ExitCode, im.MsgRct.Return)
|
||||||
printInternalExecutions(prefix+"\t", im.Subcalls)
|
printInternalExecutions(prefix+"\t", im.Subcalls)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func codeStr(c cid.Cid) string {
|
var compStateTemplate = `
|
||||||
cmh, err := multihash.Decode(c.Hash())
|
<html>
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return string(cmh.Digest)
|
|
||||||
}
|
|
||||||
|
|
||||||
func computeStateHtml(ts *types.TipSet, o *api.ComputeStateOutput, getCode func(addr address.Address) (cid.Cid, error)) error {
|
|
||||||
fmt.Printf(`<html>
|
|
||||||
<head>
|
<head>
|
||||||
<style>
|
<style>
|
||||||
html, body { font-family: monospace; }
|
html, body { font-family: monospace; }
|
||||||
@@ -987,120 +966,259 @@ func computeStateHtml(ts *types.TipSet, o *api.ComputeStateOutput, getCode func(
|
|||||||
}
|
}
|
||||||
.slow-true-false { color: #660; }
|
.slow-true-false { color: #660; }
|
||||||
.slow-true-true { color: #f80; }
|
.slow-true-true { color: #f80; }
|
||||||
|
.deemp { color: #444; }
|
||||||
|
table {
|
||||||
|
font-size: 12px;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
tr {
|
||||||
|
border-top: 1px solid black;
|
||||||
|
border-bottom: 1px solid black;
|
||||||
|
}
|
||||||
|
tr.sum { border-top: 2px solid black; }
|
||||||
|
tr:first-child { border-top: none; }
|
||||||
|
tr:last-child { border-bottom: none; }
|
||||||
|
|
||||||
|
|
||||||
|
.ellipsis-content,
|
||||||
|
.ellipsis-toggle input {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.ellipsis-toggle {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
Checked State
|
||||||
|
**/
|
||||||
|
|
||||||
|
.ellipsis-toggle input:checked + .ellipsis {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.ellipsis-toggle input:checked ~ .ellipsis-content {
|
||||||
|
display: inline;
|
||||||
|
background-color: #ddd;
|
||||||
|
}
|
||||||
|
hr {
|
||||||
|
border: none;
|
||||||
|
height: 1px;
|
||||||
|
background-color: black;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div>Tipset: <b>%s</b></div>
|
<div>Tipset: <b>{{.TipSet.Key}}</b></div>
|
||||||
<div>Height: %d</div>
|
<div>Epoch: {{.TipSet.Height}}</div>
|
||||||
<div>State CID: <b>%s</b></div>
|
<div>State CID: <b>{{.Comp.Root}}</b></div>
|
||||||
<div>Calls</div>`, ts.Key(), ts.Height(), o.Root)
|
<div>Calls</div>
|
||||||
|
{{range .Comp.Trace}}
|
||||||
|
{{template "message" (Call .ExecutionTrace false .Msg.Cid.String)}}
|
||||||
|
{{end}}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`
|
||||||
|
|
||||||
for _, ir := range o.Trace {
|
var compStateMsg = `
|
||||||
toCode, err := getCode(ir.Msg.To)
|
<div class="exec" id="{{.Hash}}">
|
||||||
if err != nil {
|
{{$code := GetCode .Msg.To}}
|
||||||
return xerrors.Errorf("getting code for %s: %w", toCode, err)
|
<div>
|
||||||
}
|
<a href="#{{.Hash}}">
|
||||||
|
{{if not .Subcall}}
|
||||||
|
<h2 class="call">
|
||||||
|
{{else}}
|
||||||
|
<h4 class="call">
|
||||||
|
{{end}}
|
||||||
|
{{- CodeStr $code}}:{{GetMethod ($code) (.Msg.Method)}}
|
||||||
|
{{if not .Subcall}}
|
||||||
|
</h2>
|
||||||
|
{{else}}
|
||||||
|
</h4>
|
||||||
|
{{end}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
params, err := jsonParams(toCode, ir.Msg.Method, ir.Msg.Params)
|
<div><b>{{.Msg.From}}</b> -> <b>{{.Msg.To}}</b> ({{ToFil .Msg.Value}} FIL), M{{.Msg.Method}}</div>
|
||||||
if err != nil {
|
{{if not .Subcall}}<div><small>Msg CID: {{.Msg.Cid}}</small></div>{{end}}
|
||||||
return xerrors.Errorf("decoding params: %w", err)
|
{{if gt (len .Msg.Params) 0}}
|
||||||
}
|
<div><pre class="params">{{JsonParams ($code) (.Msg.Method) (.Msg.Params) | html}}</pre></div>
|
||||||
|
{{end}}
|
||||||
|
<div><span class="slow-{{IsSlow .Duration}}-{{IsVerySlow .Duration}}">Took {{.Duration}}</span>, <span class="exit{{IntExit .MsgRct.ExitCode}}">Exit: <b>{{.MsgRct.ExitCode}}</b></span>{{if gt (len .MsgRct.Return) 0}}, Return{{end}}</div>
|
||||||
|
|
||||||
|
{{if gt (len .MsgRct.Return) 0}}
|
||||||
|
<div><pre class="ret">{{JsonReturn ($code) (.Msg.Method) (.MsgRct.Return) | html}}</pre></div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
if len(ir.Msg.Params) != 0 {
|
{{if ne .MsgRct.ExitCode 0}}
|
||||||
params = `<div><pre class="params">` + params + `</pre></div>`
|
<div class="error">Error: <pre>{{.Error}}</pre></div>
|
||||||
} else {
|
{{end}}
|
||||||
params = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
ret, err := jsonReturn(toCode, ir.Msg.Method, ir.MsgRct.Return)
|
<details>
|
||||||
if err != nil {
|
<summary>Gas Trace</summary>
|
||||||
return xerrors.Errorf("decoding return value: %w", err)
|
<table>
|
||||||
}
|
<tr><th>Name</th><th>Total/Compute/Storage</th><th>Time Taken</th><th>Location</th></tr>
|
||||||
|
{{define "virt" -}}
|
||||||
|
{{- if . -}}
|
||||||
|
<span class="deemp">+({{.}})</span>
|
||||||
|
{{- end -}}
|
||||||
|
{{- end}}
|
||||||
|
|
||||||
if len(ir.MsgRct.Return) == 0 {
|
{{define "gasC" -}}
|
||||||
ret = "</div>"
|
<td>{{.TotalGas}}{{template "virt" .TotalVirtualGas }}/{{.ComputeGas}}{{template "virt" .VirtualComputeGas}}/{{.StorageGas}}{{template "virt" .VirtualStorageGas}}</td>
|
||||||
} else {
|
{{- end}}
|
||||||
ret = `, Return</div><div><pre class="ret">` + ret + `</pre></div>`
|
|
||||||
}
|
|
||||||
|
|
||||||
slow := ir.Duration > 10*time.Millisecond
|
{{range .GasCharges}}
|
||||||
veryslow := ir.Duration > 50*time.Millisecond
|
<tr><td>{{.Name}}{{if .Extra}}:{{.Extra}}{{end}}</td>
|
||||||
|
{{template "gasC" .}}
|
||||||
|
<td>{{.TimeTaken}}</td>
|
||||||
|
<td>
|
||||||
|
{{ $fImp := FirstImportant .Location }}
|
||||||
|
{{ if $fImp }}
|
||||||
|
<details>
|
||||||
|
<summary>{{ $fImp }}</summary><hr />
|
||||||
|
{{ $elipOn := false }}
|
||||||
|
{{ range $index, $ele := .Location -}}
|
||||||
|
{{- if $index }}<br />{{end -}}
|
||||||
|
{{- if .Show -}}
|
||||||
|
{{ if $elipOn }}
|
||||||
|
{{ $elipOn = false }}
|
||||||
|
</span></label>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
cid := ir.Msg.Cid()
|
{{- if .Important }}<b>{{end -}}
|
||||||
|
{{- . -}}
|
||||||
|
{{if .Important }}</b>{{end}}
|
||||||
|
{{else}}
|
||||||
|
{{ if not $elipOn }}
|
||||||
|
{{ $elipOn = true }}
|
||||||
|
<label class="ellipsis-toggle"><input type="checkbox" /><span class="ellipsis">[…]<br /></span>
|
||||||
|
<span class="ellipsis-content">
|
||||||
|
{{end}}
|
||||||
|
{{- "" -}}
|
||||||
|
{{- . -}}
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
{{ if $elipOn }}
|
||||||
|
{{ $elipOn = false }}
|
||||||
|
</span></label>
|
||||||
|
{{end}}
|
||||||
|
</details>
|
||||||
|
{{end}}
|
||||||
|
</td></tr>
|
||||||
|
{{end}}
|
||||||
|
{{with SumGas .GasCharges}}
|
||||||
|
<tr class="sum"><td><b>Sum</b></td>
|
||||||
|
{{template "gasC" .}}
|
||||||
|
<td>{{.TimeTaken}}</td>
|
||||||
|
<td></td></tr>
|
||||||
|
{{end}}
|
||||||
|
</table>
|
||||||
|
</details>
|
||||||
|
|
||||||
fmt.Printf(`<div class="exec" id="%s">
|
|
||||||
<div><a href="#%s"><h2 class="call">%s:%s</h2></a></div>
|
|
||||||
<div><b>%s</b> -> <b>%s</b> (%s FIL), M%d</div>
|
|
||||||
<div><small>Msg CID: %s</small></div>
|
|
||||||
%s
|
|
||||||
<div><span class="slow-%t-%t">Took %s</span>, <span class="exit%d">Exit: <b>%d</b></span>%s
|
|
||||||
`, cid, cid, codeStr(toCode), methods[toCode][ir.Msg.Method].name, ir.Msg.From, ir.Msg.To, types.FIL(ir.Msg.Value), ir.Msg.Method, cid, params, slow, veryslow, ir.Duration, ir.MsgRct.ExitCode, ir.MsgRct.ExitCode, ret)
|
|
||||||
if ir.MsgRct.ExitCode != 0 {
|
|
||||||
fmt.Printf(`<div class="error">Error: <pre>%s</pre></div>`, ir.Error)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(ir.InternalExecutions) > 0 {
|
{{if gt (len .Subcalls) 0}}
|
||||||
fmt.Println("<div>Internal executions:</div>")
|
<div>Subcalls:</div>
|
||||||
if err := printInternalExecutionsHtml(ir.InternalExecutions, getCode); err != nil {
|
{{$hash := .Hash}}
|
||||||
return err
|
{{range .Subcalls}}
|
||||||
}
|
{{template "message" (Call . true (printf "%s-%s" $hash .Msg.Cid.String))}}
|
||||||
}
|
{{end}}
|
||||||
fmt.Println("</div>")
|
{{end}}
|
||||||
}
|
</div>`
|
||||||
|
|
||||||
fmt.Printf(`</body>
|
type compStateHTMLIn struct {
|
||||||
</html>`)
|
TipSet *types.TipSet
|
||||||
return nil
|
Comp *api.ComputeStateOutput
|
||||||
}
|
}
|
||||||
|
|
||||||
func printInternalExecutionsHtml(trace []*types.ExecutionResult, getCode func(addr address.Address) (cid.Cid, error)) error {
|
func computeStateHTMLTempl(ts *types.TipSet, o *api.ComputeStateOutput, getCode func(addr address.Address) (cid.Cid, error)) error {
|
||||||
for _, im := range trace {
|
t, err := template.New("compute_state").Funcs(map[string]interface{}{
|
||||||
toCode, err := getCode(im.Msg.To)
|
"GetCode": getCode,
|
||||||
if err != nil {
|
"GetMethod": getMethod,
|
||||||
return xerrors.Errorf("getting code for %s: %w", toCode, err)
|
"ToFil": toFil,
|
||||||
}
|
"JsonParams": jsonParams,
|
||||||
|
"JsonReturn": jsonReturn,
|
||||||
params, err := jsonParams(toCode, im.Msg.Method, im.Msg.Params)
|
"IsSlow": isSlow,
|
||||||
if err != nil {
|
"IsVerySlow": isVerySlow,
|
||||||
return xerrors.Errorf("decoding params: %w", err)
|
"IntExit": func(i exitcode.ExitCode) int64 { return int64(i) },
|
||||||
}
|
"SumGas": sumGas,
|
||||||
|
"CodeStr": codeStr,
|
||||||
if len(im.Msg.Params) != 0 {
|
"Call": call,
|
||||||
params = `<div><pre class="params">` + params + `</pre></div>`
|
"FirstImportant": func(locs []types.Loc) *types.Loc {
|
||||||
} else {
|
if len(locs) != 0 {
|
||||||
params = ""
|
for _, l := range locs {
|
||||||
}
|
if l.Important() {
|
||||||
|
return &l
|
||||||
ret, err := jsonReturn(toCode, im.Msg.Method, im.MsgRct.Return)
|
}
|
||||||
if err != nil {
|
}
|
||||||
return xerrors.Errorf("decoding return value: %w", err)
|
return &locs[0]
|
||||||
}
|
|
||||||
|
|
||||||
if len(im.MsgRct.Return) == 0 {
|
|
||||||
ret = "</div>"
|
|
||||||
} else {
|
|
||||||
ret = `, Return</div><div><pre class="ret">` + ret + `</pre></div>`
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf(`<div class="exec">
|
|
||||||
<div><h4 class="call">%s:%s</h4></div>
|
|
||||||
<div><b>%s</b> -> <b>%s</b> (%s FIL), M%d</div>
|
|
||||||
%s
|
|
||||||
<div><span class="exit%d">Exit: <b>%d</b></span>%s
|
|
||||||
`, codeStr(toCode), methods[toCode][im.Msg.Method].name, im.Msg.From, im.Msg.To, types.FIL(im.Msg.Value), im.Msg.Method, params, im.MsgRct.ExitCode, im.MsgRct.ExitCode, ret)
|
|
||||||
if im.MsgRct.ExitCode != 0 {
|
|
||||||
fmt.Printf(`<div class="error">Error: <pre>%s</pre></div>`, im.Error)
|
|
||||||
}
|
|
||||||
if len(im.Subcalls) > 0 {
|
|
||||||
fmt.Println("<div>Subcalls:</div>")
|
|
||||||
if err := printInternalExecutionsHtml(im.Subcalls, getCode); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
}
|
return nil
|
||||||
fmt.Println("</div>")
|
},
|
||||||
|
}).Parse(compStateTemplate)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
t, err = t.New("message").Parse(compStateMsg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return t.ExecuteTemplate(os.Stdout, "compute_state", &compStateHTMLIn{
|
||||||
|
TipSet: ts,
|
||||||
|
Comp: o,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type callMeta struct {
|
||||||
|
types.ExecutionTrace
|
||||||
|
Subcall bool
|
||||||
|
Hash string
|
||||||
|
}
|
||||||
|
|
||||||
|
func call(e types.ExecutionTrace, subcall bool, hash string) callMeta {
|
||||||
|
return callMeta{
|
||||||
|
ExecutionTrace: e,
|
||||||
|
Subcall: subcall,
|
||||||
|
Hash: hash,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func codeStr(c cid.Cid) string {
|
||||||
|
cmh, err := multihash.Decode(c.Hash())
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return string(cmh.Digest)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMethod(code cid.Cid, method abi.MethodNum) string {
|
||||||
|
return methods[code][method].Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func toFil(f types.BigInt) types.FIL {
|
||||||
|
return types.FIL(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isSlow(t time.Duration) bool {
|
||||||
|
return t > 10*time.Millisecond
|
||||||
|
}
|
||||||
|
|
||||||
|
func isVerySlow(t time.Duration) bool {
|
||||||
|
return t > 50*time.Millisecond
|
||||||
|
}
|
||||||
|
|
||||||
|
func sumGas(changes []*types.GasTrace) types.GasTrace {
|
||||||
|
var out types.GasTrace
|
||||||
|
for _, gc := range changes {
|
||||||
|
out.TotalGas += gc.TotalGas
|
||||||
|
out.ComputeGas += gc.ComputeGas
|
||||||
|
out.StorageGas += gc.StorageGas
|
||||||
|
|
||||||
|
out.TotalVirtualGas += gc.TotalVirtualGas
|
||||||
|
out.VirtualComputeGas += gc.VirtualComputeGas
|
||||||
|
out.VirtualStorageGas += gc.VirtualStorageGas
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
func jsonParams(code cid.Cid, method abi.MethodNum, params []byte) (string, error) {
|
func jsonParams(code cid.Cid, method abi.MethodNum, params []byte) (string, error) {
|
||||||
@@ -1153,7 +1271,7 @@ var stateWaitMsgCmd = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
mw, err := api.StateWaitMsg(ctx, msg)
|
mw, err := api.StateWaitMsg(ctx, msg, build.MessageConfidence)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -7,7 +7,7 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||||
cid "github.com/ipfs/go-cid"
|
cid "github.com/ipfs/go-cid"
|
||||||
"gopkg.in/urfave/cli.v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
@@ -186,7 +186,7 @@ func SyncWait(ctx context.Context, napi api.FullNode) error {
|
|||||||
|
|
||||||
fmt.Printf("\r\x1b[2KWorker %d: Target: %s\tState: %s\tHeight: %d", working, target, chain.SyncStageString(ss.Stage), ss.Height)
|
fmt.Printf("\r\x1b[2KWorker %d: Target: %s\tState: %s\tHeight: %d", working, target, chain.SyncStageString(ss.Stage), ss.Height)
|
||||||
|
|
||||||
if time.Now().Unix()-int64(head.MinTimestamp()) < build.BlockDelay {
|
if time.Now().Unix()-int64(head.MinTimestamp()) < int64(build.BlockDelaySecs) {
|
||||||
fmt.Println("\nDone!")
|
fmt.Println("\nDone!")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ package cli
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"gopkg.in/urfave/cli.v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var versionCmd = &cli.Command{
|
var versionCmd = &cli.Command{
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gopkg.in/urfave/cli.v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var waitApiCmd = &cli.Command{
|
var waitApiCmd = &cli.Command{
|
||||||
|
|||||||
+33
-2
@@ -15,7 +15,7 @@ import (
|
|||||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"gopkg.in/urfave/cli.v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var walletCmd = &cli.Command{
|
var walletCmd = &cli.Command{
|
||||||
@@ -31,6 +31,7 @@ var walletCmd = &cli.Command{
|
|||||||
walletSetDefault,
|
walletSetDefault,
|
||||||
walletSign,
|
walletSign,
|
||||||
walletVerify,
|
walletVerify,
|
||||||
|
walletDelete,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +113,12 @@ var walletBalance = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("%s\n", types.FIL(balance))
|
if balance.Equals(types.NewInt(0)) {
|
||||||
|
fmt.Printf("%s (warning: may display 0 if chain sync in progress)\n", types.FIL(balance))
|
||||||
|
} else {
|
||||||
|
fmt.Printf("%s\n", types.FIL(balance))
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -375,3 +381,28 @@ var walletVerify = &cli.Command{
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var walletDelete = &cli.Command{
|
||||||
|
Name: "delete",
|
||||||
|
Usage: "Delete an account from the wallet",
|
||||||
|
ArgsUsage: "<address> ",
|
||||||
|
Action: func(cctx *cli.Context) error {
|
||||||
|
api, closer, err := GetFullNodeAPI(cctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer closer()
|
||||||
|
ctx := ReqContext(cctx)
|
||||||
|
|
||||||
|
if !cctx.Args().Present() || cctx.NArg() != 1 {
|
||||||
|
return fmt.Errorf("must specify address to delete")
|
||||||
|
}
|
||||||
|
|
||||||
|
addr, err := address.NewFromString(cctx.Args().First())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return api.WalletDelete(ctx, addr)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
lcli "github.com/filecoin-project/lotus/cli"
|
lcli "github.com/filecoin-project/lotus/cli"
|
||||||
|
|
||||||
"gopkg.in/urfave/cli.v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
+438
-27
@@ -1,11 +1,17 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"math"
|
||||||
|
"net/http"
|
||||||
|
_ "net/http/pprof"
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
"runtime/pprof"
|
"runtime/pprof"
|
||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
@@ -24,7 +30,7 @@ import (
|
|||||||
"github.com/ipfs/go-datastore"
|
"github.com/ipfs/go-datastore"
|
||||||
badger "github.com/ipfs/go-ds-badger2"
|
badger "github.com/ipfs/go-ds-badger2"
|
||||||
blockstore "github.com/ipfs/go-ipfs-blockstore"
|
blockstore "github.com/ipfs/go-ipfs-blockstore"
|
||||||
"gopkg.in/urfave/cli.v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TipSetExec struct {
|
type TipSetExec struct {
|
||||||
@@ -44,8 +50,14 @@ var importBenchCmd = &cli.Command{
|
|||||||
Name: "height",
|
Name: "height",
|
||||||
Usage: "halt validation after given height",
|
Usage: "halt validation after given height",
|
||||||
},
|
},
|
||||||
|
&cli.IntFlag{
|
||||||
|
Name: "batch-seal-verify-threads",
|
||||||
|
Usage: "set the parallelism factor for batch seal verification",
|
||||||
|
Value: runtime.NumCPU(),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
|
vm.BatchSealVerifyParallelism = cctx.Int("batch-seal-verify-threads")
|
||||||
if !cctx.Args().Present() {
|
if !cctx.Args().Present() {
|
||||||
fmt.Println("must pass car file of chain to benchmark importing")
|
fmt.Println("must pass car file of chain to benchmark importing")
|
||||||
return nil
|
return nil
|
||||||
@@ -111,14 +123,22 @@ var importBenchCmd = &cli.Command{
|
|||||||
ts = next
|
ts = next
|
||||||
}
|
}
|
||||||
|
|
||||||
out := make([]TipSetExec, 0, len(tschain))
|
ibj, err := os.Create("import-bench.json")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer ibj.Close() //nolint:errcheck
|
||||||
|
|
||||||
|
enc := json.NewEncoder(ibj)
|
||||||
|
|
||||||
|
var lastTse *TipSetExec
|
||||||
|
|
||||||
lastState := tschain[len(tschain)-1].ParentState()
|
lastState := tschain[len(tschain)-1].ParentState()
|
||||||
for i := len(tschain) - 2; i >= 0; i-- {
|
for i := len(tschain) - 2; i >= 0; i-- {
|
||||||
cur := tschain[i]
|
cur := tschain[i]
|
||||||
log.Infof("computing state (height: %d, ts=%s)", cur.Height(), cur.Cids())
|
log.Infof("computing state (height: %d, ts=%s)", cur.Height(), cur.Cids())
|
||||||
if cur.ParentState() != lastState {
|
if cur.ParentState() != lastState {
|
||||||
lastTrace := out[len(out)-1].Trace
|
lastTrace := lastTse.Trace
|
||||||
d, err := json.MarshalIndent(lastTrace, "", " ")
|
d, err := json.MarshalIndent(lastTrace, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@@ -132,36 +152,301 @@ var importBenchCmd = &cli.Command{
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
out = append(out, TipSetExec{
|
stripCallers(trace)
|
||||||
|
|
||||||
|
lastTse = &TipSetExec{
|
||||||
TipSet: cur.Key(),
|
TipSet: cur.Key(),
|
||||||
Trace: trace,
|
Trace: trace,
|
||||||
Duration: time.Since(start),
|
Duration: time.Since(start),
|
||||||
})
|
}
|
||||||
lastState = st
|
lastState = st
|
||||||
|
if err := enc.Encode(lastTse); err != nil {
|
||||||
|
return xerrors.Errorf("failed to write out tipsetexec: %w", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pprof.StopCPUProfile()
|
pprof.StopCPUProfile()
|
||||||
|
|
||||||
ibj, err := os.Create("import-bench.json")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer ibj.Close() //nolint:errcheck
|
|
||||||
|
|
||||||
if err := json.NewEncoder(ibj).Encode(out); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func walkExecutionTrace(et *types.ExecutionTrace) {
|
||||||
|
for _, gc := range et.GasCharges {
|
||||||
|
gc.Callers = nil
|
||||||
|
}
|
||||||
|
for _, sub := range et.Subcalls {
|
||||||
|
walkExecutionTrace(&sub) //nolint:scopelint,gosec
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func stripCallers(trace []*api.InvocResult) {
|
||||||
|
for _, t := range trace {
|
||||||
|
walkExecutionTrace(&t.ExecutionTrace)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type Invocation struct {
|
type Invocation struct {
|
||||||
TipSet types.TipSetKey
|
TipSet types.TipSetKey
|
||||||
Invoc *api.InvocResult
|
Invoc *api.InvocResult
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const GasPerNs = 10
|
||||||
|
|
||||||
|
func countGasCosts(et *types.ExecutionTrace) (int64, int64) {
|
||||||
|
var cgas, vgas int64
|
||||||
|
|
||||||
|
for _, gc := range et.GasCharges {
|
||||||
|
cgas += gc.ComputeGas
|
||||||
|
vgas += gc.VirtualComputeGas
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, sub := range et.Subcalls {
|
||||||
|
c, v := countGasCosts(&sub)
|
||||||
|
cgas += c
|
||||||
|
vgas += v
|
||||||
|
}
|
||||||
|
|
||||||
|
return cgas, vgas
|
||||||
|
}
|
||||||
|
|
||||||
|
func compStats(vals []float64) (float64, float64) {
|
||||||
|
var sum float64
|
||||||
|
|
||||||
|
for _, v := range vals {
|
||||||
|
sum += v
|
||||||
|
}
|
||||||
|
|
||||||
|
av := sum / float64(len(vals))
|
||||||
|
|
||||||
|
var varsum float64
|
||||||
|
for _, v := range vals {
|
||||||
|
delta := av - v
|
||||||
|
varsum += delta * delta
|
||||||
|
}
|
||||||
|
|
||||||
|
return av, math.Sqrt(varsum / float64(len(vals)))
|
||||||
|
}
|
||||||
|
|
||||||
|
type stats struct {
|
||||||
|
timeTaken meanVar
|
||||||
|
gasRatio meanVar
|
||||||
|
|
||||||
|
extraCovar *covar
|
||||||
|
}
|
||||||
|
|
||||||
|
type covar struct {
|
||||||
|
meanX float64
|
||||||
|
meanY float64
|
||||||
|
c float64
|
||||||
|
n float64
|
||||||
|
m2x float64
|
||||||
|
m2y float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cov1 *covar) Covariance() float64 {
|
||||||
|
return cov1.c / (cov1.n - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cov1 *covar) VarianceX() float64 {
|
||||||
|
return cov1.m2x / (cov1.n - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v1 *covar) StddevX() float64 {
|
||||||
|
return math.Sqrt(v1.VarianceX())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cov1 *covar) VarianceY() float64 {
|
||||||
|
return cov1.m2y / (cov1.n - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v1 *covar) StddevY() float64 {
|
||||||
|
return math.Sqrt(v1.VarianceY())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cov1 *covar) AddPoint(x, y float64) {
|
||||||
|
cov1.n += 1
|
||||||
|
|
||||||
|
dx := x - cov1.meanX
|
||||||
|
cov1.meanX += dx / cov1.n
|
||||||
|
dx2 := x - cov1.meanX
|
||||||
|
cov1.m2x += dx * dx2
|
||||||
|
|
||||||
|
dy := y - cov1.meanY
|
||||||
|
cov1.meanY += dy / cov1.n
|
||||||
|
dy2 := y - cov1.meanY
|
||||||
|
cov1.m2y += dy * dy2
|
||||||
|
|
||||||
|
cov1.c += dx * dy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cov1 *covar) Combine(cov2 *covar) {
|
||||||
|
if cov1.n == 0 {
|
||||||
|
*cov1 = *cov2
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if cov2.n == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if cov1.n == 1 {
|
||||||
|
cpy := *cov2
|
||||||
|
cpy.AddPoint(cov2.meanX, cov2.meanY)
|
||||||
|
*cov1 = cpy
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if cov2.n == 1 {
|
||||||
|
cov1.AddPoint(cov2.meanX, cov2.meanY)
|
||||||
|
}
|
||||||
|
|
||||||
|
out := covar{}
|
||||||
|
out.n = cov1.n + cov2.n
|
||||||
|
|
||||||
|
dx := cov1.meanX - cov2.meanX
|
||||||
|
out.meanX = cov1.meanX - dx*cov2.n/out.n
|
||||||
|
out.m2x = cov1.m2x + cov2.m2x + dx*dx*cov1.n*cov2.n/out.n
|
||||||
|
|
||||||
|
dy := cov1.meanY - cov2.meanY
|
||||||
|
out.meanY = cov1.meanY - dy*cov2.n/out.n
|
||||||
|
out.m2y = cov1.m2y + cov2.m2y + dy*dy*cov1.n*cov2.n/out.n
|
||||||
|
|
||||||
|
out.c = cov1.c + cov2.c + dx*dy*cov1.n*cov2.n/out.n
|
||||||
|
*cov1 = out
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cov1 *covar) A() float64 {
|
||||||
|
return cov1.Covariance() / cov1.VarianceX()
|
||||||
|
}
|
||||||
|
func (cov1 *covar) B() float64 {
|
||||||
|
return cov1.meanY - cov1.meanX*cov1.A()
|
||||||
|
}
|
||||||
|
func (cov1 *covar) Correl() float64 {
|
||||||
|
return cov1.Covariance() / cov1.StddevX() / cov1.StddevY()
|
||||||
|
}
|
||||||
|
|
||||||
|
type meanVar struct {
|
||||||
|
n float64
|
||||||
|
mean float64
|
||||||
|
m2 float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v1 *meanVar) AddPoint(value float64) {
|
||||||
|
// based on https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford's_online_algorithm
|
||||||
|
v1.n += 1
|
||||||
|
delta := value - v1.mean
|
||||||
|
v1.mean += delta / v1.n
|
||||||
|
delta2 := value - v1.mean
|
||||||
|
v1.m2 += delta * delta2
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v1 *meanVar) Variance() float64 {
|
||||||
|
return v1.m2 / (v1.n - 1)
|
||||||
|
}
|
||||||
|
func (v1 *meanVar) Mean() float64 {
|
||||||
|
return v1.mean
|
||||||
|
}
|
||||||
|
func (v1 *meanVar) Stddev() float64 {
|
||||||
|
return math.Sqrt(v1.Variance())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v1 *meanVar) Combine(v2 *meanVar) {
|
||||||
|
if v1.n == 0 {
|
||||||
|
*v1 = *v2
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if v2.n == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if v1.n == 1 {
|
||||||
|
cpy := *v2
|
||||||
|
cpy.AddPoint(v1.mean)
|
||||||
|
*v1 = cpy
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if v2.n == 1 {
|
||||||
|
v1.AddPoint(v2.mean)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
newCount := v1.n + v2.n
|
||||||
|
delta := v2.mean - v1.mean
|
||||||
|
meanDelta := delta * v2.n / newCount
|
||||||
|
m2 := v1.m2 + v2.m2 + delta*meanDelta*v1.n
|
||||||
|
v1.n = newCount
|
||||||
|
v1.mean += meanDelta
|
||||||
|
v1.m2 = m2
|
||||||
|
}
|
||||||
|
|
||||||
|
func getExtras(ex interface{}) (*string, *float64) {
|
||||||
|
if t, ok := ex.(string); ok {
|
||||||
|
return &t, nil
|
||||||
|
}
|
||||||
|
if size, ok := ex.(float64); ok {
|
||||||
|
return nil, &size
|
||||||
|
}
|
||||||
|
if exMap, ok := ex.(map[string]interface{}); ok {
|
||||||
|
t, tok := exMap["type"].(string)
|
||||||
|
size, sok := exMap["size"].(float64)
|
||||||
|
if tok && sok {
|
||||||
|
return &t, &size
|
||||||
|
}
|
||||||
|
if tok {
|
||||||
|
return &t, nil
|
||||||
|
}
|
||||||
|
if sok {
|
||||||
|
return nil, &size
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func tallyGasCharges(charges map[string]*stats, et types.ExecutionTrace) {
|
||||||
|
for i, gc := range et.GasCharges {
|
||||||
|
name := gc.Name
|
||||||
|
if name == "OnIpldGetStart" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
tt := float64(gc.TimeTaken.Nanoseconds())
|
||||||
|
if name == "OnIpldGet" {
|
||||||
|
prev := et.GasCharges[i-1]
|
||||||
|
if prev.Name != "OnIpldGetStart" {
|
||||||
|
log.Warn("OnIpldGet without OnIpldGetStart")
|
||||||
|
}
|
||||||
|
tt += float64(prev.TimeTaken.Nanoseconds())
|
||||||
|
}
|
||||||
|
eType, eSize := getExtras(gc.Extra)
|
||||||
|
if eType != nil {
|
||||||
|
name += "-" + *eType
|
||||||
|
}
|
||||||
|
compGas := gc.VirtualComputeGas
|
||||||
|
if compGas == 0 {
|
||||||
|
compGas = 1
|
||||||
|
}
|
||||||
|
s := charges[name]
|
||||||
|
if s == nil {
|
||||||
|
s = new(stats)
|
||||||
|
charges[name] = s
|
||||||
|
}
|
||||||
|
|
||||||
|
if eSize != nil {
|
||||||
|
if s.extraCovar == nil {
|
||||||
|
s.extraCovar = &covar{}
|
||||||
|
}
|
||||||
|
s.extraCovar.AddPoint(*eSize, tt)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.timeTaken.AddPoint(tt)
|
||||||
|
|
||||||
|
ratio := tt / float64(compGas) * GasPerNs
|
||||||
|
s.gasRatio.AddPoint(ratio)
|
||||||
|
}
|
||||||
|
for _, sub := range et.Subcalls {
|
||||||
|
tallyGasCharges(charges, sub)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var importAnalyzeCmd = &cli.Command{
|
var importAnalyzeCmd = &cli.Command{
|
||||||
Name: "analyze",
|
Name: "analyze",
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
@@ -170,27 +455,142 @@ var importAnalyzeCmd = &cli.Command{
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
http.ListenAndServe("localhost:6060", nil)
|
||||||
|
}()
|
||||||
|
|
||||||
fi, err := os.Open(cctx.Args().First())
|
fi, err := os.Open(cctx.Args().First())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var results []TipSetExec
|
const nWorkers = 16
|
||||||
if err := json.NewDecoder(fi).Decode(&results); err != nil {
|
jsonIn := make(chan []byte, 2*nWorkers)
|
||||||
return err
|
type result struct {
|
||||||
|
totalTime time.Duration
|
||||||
|
chargeStats map[string]*stats
|
||||||
|
expensiveInvocs []Invocation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
results := make(chan result, nWorkers)
|
||||||
|
|
||||||
|
for i := 0; i < nWorkers; i++ {
|
||||||
|
go func() {
|
||||||
|
chargeStats := make(map[string]*stats)
|
||||||
|
var totalTime time.Duration
|
||||||
|
const invocsKeep = 32
|
||||||
|
var expensiveInvocs = make([]Invocation, 0, 8*invocsKeep)
|
||||||
|
var leastExpensiveInvoc = time.Duration(0)
|
||||||
|
|
||||||
|
for {
|
||||||
|
b, ok := <-jsonIn
|
||||||
|
if !ok {
|
||||||
|
results <- result{
|
||||||
|
totalTime: totalTime,
|
||||||
|
chargeStats: chargeStats,
|
||||||
|
expensiveInvocs: expensiveInvocs,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var tse TipSetExec
|
||||||
|
err := json.Unmarshal(b, &tse)
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("error unmarshaling tipset: %+v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
totalTime += tse.Duration
|
||||||
|
for _, inv := range tse.Trace {
|
||||||
|
if inv.Duration > leastExpensiveInvoc {
|
||||||
|
expensiveInvocs = append(expensiveInvocs, Invocation{
|
||||||
|
TipSet: tse.TipSet,
|
||||||
|
Invoc: inv,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
tallyGasCharges(chargeStats, inv.ExecutionTrace)
|
||||||
|
}
|
||||||
|
if len(expensiveInvocs) > 4*invocsKeep {
|
||||||
|
sort.Slice(expensiveInvocs, func(i, j int) bool {
|
||||||
|
return expensiveInvocs[i].Invoc.Duration > expensiveInvocs[j].Invoc.Duration
|
||||||
|
})
|
||||||
|
leastExpensiveInvoc = expensiveInvocs[len(expensiveInvocs)-1].Invoc.Duration
|
||||||
|
n := 30
|
||||||
|
if len(expensiveInvocs) < n {
|
||||||
|
n = len(expensiveInvocs)
|
||||||
|
}
|
||||||
|
expensiveInvocs = expensiveInvocs[:n]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
var totalTipsets int64
|
||||||
|
reader := bufio.NewReader(fi)
|
||||||
|
for {
|
||||||
|
b, err := reader.ReadBytes('\n')
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
if e, ok := err.(*json.SyntaxError); ok {
|
||||||
|
log.Warnf("syntax error at byte offset %d", e.Offset)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
totalTipsets++
|
||||||
|
jsonIn <- b
|
||||||
|
fmt.Fprintf(os.Stderr, "\rProcessed %d tipsets", totalTipsets)
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(jsonIn)
|
||||||
|
fmt.Fprintf(os.Stderr, "\n")
|
||||||
|
fmt.Fprintf(os.Stderr, "Collecting results\n")
|
||||||
|
|
||||||
var invocs []Invocation
|
var invocs []Invocation
|
||||||
var totalTime time.Duration
|
var totalTime time.Duration
|
||||||
for i, r := range results {
|
var keys []string
|
||||||
_ = i
|
var charges = make(map[string]*stats)
|
||||||
totalTime += r.Duration
|
for i := 0; i < nWorkers; i++ {
|
||||||
|
fmt.Fprintf(os.Stderr, "\rProcessing results from worker %d/%d", i+1, nWorkers)
|
||||||
|
res := <-results
|
||||||
|
invocs = append(invocs, res.expensiveInvocs...)
|
||||||
|
for k, v := range res.chargeStats {
|
||||||
|
s := charges[k]
|
||||||
|
if s == nil {
|
||||||
|
s = new(stats)
|
||||||
|
charges[k] = s
|
||||||
|
}
|
||||||
|
s.timeTaken.Combine(&v.timeTaken)
|
||||||
|
s.gasRatio.Combine(&v.gasRatio)
|
||||||
|
|
||||||
for _, inv := range r.Trace {
|
if v.extraCovar != nil {
|
||||||
invocs = append(invocs, Invocation{
|
if s.extraCovar == nil {
|
||||||
TipSet: r.TipSet,
|
s.extraCovar = &covar{}
|
||||||
Invoc: inv,
|
}
|
||||||
})
|
s.extraCovar.Combine(v.extraCovar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
totalTime += res.totalTime
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(os.Stderr, "\nCollecting gas keys\n")
|
||||||
|
for k := range charges {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Gas Price Deltas")
|
||||||
|
sort.Strings(keys)
|
||||||
|
for _, k := range keys {
|
||||||
|
s := charges[k]
|
||||||
|
fmt.Printf("%s: incr by %.4f~%.4f; tt %.4f~%.4f\n", k, s.gasRatio.Mean(), s.gasRatio.Stddev(),
|
||||||
|
s.timeTaken.Mean(), s.timeTaken.Stddev())
|
||||||
|
if s.extraCovar != nil {
|
||||||
|
fmt.Printf("\t correll: %.2f, tt = %.2f * extra + %.2f\n", s.extraCovar.Correl(),
|
||||||
|
s.extraCovar.A(), s.extraCovar.B())
|
||||||
|
fmt.Printf("\t covar: %.2f, extra: %.2f~%.2f, tt2: %.2f~%.2f, count %.0f\n",
|
||||||
|
s.extraCovar.Covariance(), s.extraCovar.meanX, s.extraCovar.StddevX(),
|
||||||
|
s.extraCovar.meanY, s.extraCovar.StddevY(), s.extraCovar.n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,9 +599,20 @@ var importAnalyzeCmd = &cli.Command{
|
|||||||
})
|
})
|
||||||
|
|
||||||
fmt.Println("Total time: ", totalTime)
|
fmt.Println("Total time: ", totalTime)
|
||||||
fmt.Println("Average time per epoch: ", totalTime/time.Duration(len(results)))
|
fmt.Println("Average time per epoch: ", totalTime/time.Duration(totalTipsets))
|
||||||
|
if actorExec, ok := charges["OnActorExec"]; ok {
|
||||||
|
timeInActors := actorExec.timeTaken.Mean() * actorExec.timeTaken.n
|
||||||
|
fmt.Printf("Avarage time per epoch in actors: %s (%.1f%%)\n", time.Duration(timeInActors)/time.Duration(totalTipsets), timeInActors/float64(totalTime)*100)
|
||||||
|
}
|
||||||
|
if actorExecDone, ok := charges["OnActorExecDone"]; ok {
|
||||||
|
timeInActors := actorExecDone.timeTaken.Mean() * actorExecDone.timeTaken.n
|
||||||
|
fmt.Printf("Avarage time per epoch in OnActorExecDone %s (%.1f%%)\n", time.Duration(timeInActors)/time.Duration(totalTipsets), timeInActors/float64(totalTime)*100)
|
||||||
|
}
|
||||||
|
|
||||||
n := 30
|
n := 30
|
||||||
|
if len(invocs) < n {
|
||||||
|
n = len(invocs)
|
||||||
|
}
|
||||||
fmt.Printf("Top %d most expensive calls:\n", n)
|
fmt.Printf("Top %d most expensive calls:\n", n)
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
inv := invocs[i].Invoc
|
inv := invocs[i].Invoc
|
||||||
|
|||||||
+212
-139
@@ -15,11 +15,12 @@ import (
|
|||||||
logging "github.com/ipfs/go-log/v2"
|
logging "github.com/ipfs/go-log/v2"
|
||||||
"github.com/minio/blake2b-simd"
|
"github.com/minio/blake2b-simd"
|
||||||
"github.com/mitchellh/go-homedir"
|
"github.com/mitchellh/go-homedir"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
"gopkg.in/urfave/cli.v2"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
paramfetch "github.com/filecoin-project/go-paramfetch"
|
paramfetch "github.com/filecoin-project/go-paramfetch"
|
||||||
|
lcli "github.com/filecoin-project/lotus/cli"
|
||||||
"github.com/filecoin-project/sector-storage/ffiwrapper"
|
"github.com/filecoin-project/sector-storage/ffiwrapper"
|
||||||
"github.com/filecoin-project/sector-storage/ffiwrapper/basicfs"
|
"github.com/filecoin-project/sector-storage/ffiwrapper/basicfs"
|
||||||
"github.com/filecoin-project/sector-storage/stores"
|
"github.com/filecoin-project/sector-storage/stores"
|
||||||
@@ -73,7 +74,7 @@ func main() {
|
|||||||
|
|
||||||
log.Info("Starting lotus-bench")
|
log.Info("Starting lotus-bench")
|
||||||
|
|
||||||
miner.SupportedProofTypes[abi.RegisteredProof_StackedDRG2KiBSeal] = struct{}{}
|
miner.SupportedProofTypes[abi.RegisteredSealProof_StackedDrg2KiBV1] = struct{}{}
|
||||||
|
|
||||||
app := &cli.App{
|
app := &cli.App{
|
||||||
Name: "lotus-bench",
|
Name: "lotus-bench",
|
||||||
@@ -138,6 +139,10 @@ var sealBenchCmd = &cli.Command{
|
|||||||
Name: "num-sectors",
|
Name: "num-sectors",
|
||||||
Value: 1,
|
Value: 1,
|
||||||
},
|
},
|
||||||
|
&cli.IntFlag{
|
||||||
|
Name: "parallel",
|
||||||
|
Value: 1,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
if c.Bool("no-gpu") {
|
if c.Bool("no-gpu") {
|
||||||
@@ -215,7 +220,7 @@ var sealBenchCmd = &cli.Command{
|
|||||||
|
|
||||||
// Only fetch parameters if actually needed
|
// Only fetch parameters if actually needed
|
||||||
if !c.Bool("skip-commit2") {
|
if !c.Bool("skip-commit2") {
|
||||||
if err := paramfetch.GetParams(build.ParametersJSON(), uint64(sectorSize)); err != nil {
|
if err := paramfetch.GetParams(lcli.ReqContext(c), build.ParametersJSON(), uint64(sectorSize)); err != nil {
|
||||||
return xerrors.Errorf("getting params: %w", err)
|
return xerrors.Errorf("getting params: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -234,7 +239,12 @@ var sealBenchCmd = &cli.Command{
|
|||||||
|
|
||||||
if robench == "" {
|
if robench == "" {
|
||||||
var err error
|
var err error
|
||||||
sealTimings, sealedSectors, err = runSeals(sb, sbfs, c.Int("num-sectors"), mid, sectorSize, []byte(c.String("ticket-preimage")), c.String("save-commit2-input"), c.Bool("skip-commit2"), c.Bool("skip-unseal"))
|
parCfg := ParCfg{
|
||||||
|
PreCommit1: c.Int("parallel"),
|
||||||
|
PreCommit2: 1,
|
||||||
|
Commit: 1,
|
||||||
|
}
|
||||||
|
sealTimings, sealedSectors, err = runSeals(sb, sbfs, c.Int("num-sectors"), parCfg, mid, sectorSize, []byte(c.String("ticket-preimage")), c.String("save-commit2-input"), c.Bool("skip-commit2"), c.Bool("skip-unseal"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("failed to run seals: %w", err)
|
return xerrors.Errorf("failed to run seals: %w", err)
|
||||||
}
|
}
|
||||||
@@ -269,9 +279,9 @@ var sealBenchCmd = &cli.Command{
|
|||||||
|
|
||||||
for _, s := range genm.Sectors {
|
for _, s := range genm.Sectors {
|
||||||
sealedSectors = append(sealedSectors, abi.SectorInfo{
|
sealedSectors = append(sealedSectors, abi.SectorInfo{
|
||||||
SealedCID: s.CommR,
|
SealedCID: s.CommR,
|
||||||
SectorNumber: s.SectorID,
|
SectorNumber: s.SectorID,
|
||||||
RegisteredProof: s.ProofType,
|
SealProof: s.ProofType,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -283,7 +293,12 @@ var sealBenchCmd = &cli.Command{
|
|||||||
|
|
||||||
if !c.Bool("skip-commit2") {
|
if !c.Bool("skip-commit2") {
|
||||||
log.Info("generating winning post candidates")
|
log.Info("generating winning post candidates")
|
||||||
fcandidates, err := ffiwrapper.ProofVerifier.GenerateWinningPoStSectorChallenge(context.TODO(), spt, mid, challenge[:], uint64(len(sealedSectors)))
|
wipt, err := spt.RegisteredWinningPoStProof()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fcandidates, err := ffiwrapper.ProofVerifier.GenerateWinningPoStSectorChallenge(context.TODO(), wipt, mid, challenge[:], uint64(len(sealedSectors)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -301,7 +316,7 @@ var sealBenchCmd = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
winnnigpost1 := time.Now()
|
winningpost1 := time.Now()
|
||||||
|
|
||||||
log.Info("computing winning post snark (hot)")
|
log.Info("computing winning post snark (hot)")
|
||||||
proof2, err := sb.GenerateWinningPoSt(context.TODO(), mid, candidates, challenge[:])
|
proof2, err := sb.GenerateWinningPoSt(context.TODO(), mid, candidates, challenge[:])
|
||||||
@@ -325,7 +340,7 @@ var sealBenchCmd = &cli.Command{
|
|||||||
log.Error("post verification failed")
|
log.Error("post verification failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
verifyWinnnigPost1 := time.Now()
|
verifyWinningPost1 := time.Now()
|
||||||
|
|
||||||
pvi2 := abi.WinningPoStVerifyInfo{
|
pvi2 := abi.WinningPoStVerifyInfo{
|
||||||
Randomness: abi.PoStRandomness(challenge[:]),
|
Randomness: abi.PoStRandomness(challenge[:]),
|
||||||
@@ -344,7 +359,7 @@ var sealBenchCmd = &cli.Command{
|
|||||||
verifyWinningPost2 := time.Now()
|
verifyWinningPost2 := time.Now()
|
||||||
|
|
||||||
log.Info("computing window post snark (cold)")
|
log.Info("computing window post snark (cold)")
|
||||||
wproof1, err := sb.GenerateWindowPoSt(context.TODO(), mid, sealedSectors, challenge[:])
|
wproof1, _, err := sb.GenerateWindowPoSt(context.TODO(), mid, sealedSectors, challenge[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -352,7 +367,7 @@ var sealBenchCmd = &cli.Command{
|
|||||||
windowpost1 := time.Now()
|
windowpost1 := time.Now()
|
||||||
|
|
||||||
log.Info("computing window post snark (hot)")
|
log.Info("computing window post snark (hot)")
|
||||||
wproof2, err := sb.GenerateWindowPoSt(context.TODO(), mid, sealedSectors, challenge[:])
|
wproof2, _, err := sb.GenerateWindowPoSt(context.TODO(), mid, sealedSectors, challenge[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -392,10 +407,10 @@ var sealBenchCmd = &cli.Command{
|
|||||||
verifyWindowpost2 := time.Now()
|
verifyWindowpost2 := time.Now()
|
||||||
|
|
||||||
bo.PostGenerateCandidates = gencandidates.Sub(beforePost)
|
bo.PostGenerateCandidates = gencandidates.Sub(beforePost)
|
||||||
bo.PostWinningProofCold = winnnigpost1.Sub(gencandidates)
|
bo.PostWinningProofCold = winningpost1.Sub(gencandidates)
|
||||||
bo.PostWinningProofHot = winnningpost2.Sub(winnnigpost1)
|
bo.PostWinningProofHot = winnningpost2.Sub(winningpost1)
|
||||||
bo.VerifyWinningPostCold = verifyWinnnigPost1.Sub(winnningpost2)
|
bo.VerifyWinningPostCold = verifyWinningPost1.Sub(winnningpost2)
|
||||||
bo.VerifyWinningPostHot = verifyWinningPost2.Sub(verifyWinnnigPost1)
|
bo.VerifyWinningPostHot = verifyWinningPost2.Sub(verifyWinningPost1)
|
||||||
|
|
||||||
bo.PostWindowProofCold = windowpost1.Sub(verifyWinningPost2)
|
bo.PostWindowProofCold = windowpost1.Sub(verifyWinningPost2)
|
||||||
bo.PostWindowProofHot = windowpost2.Sub(windowpost1)
|
bo.PostWindowProofHot = windowpost2.Sub(windowpost1)
|
||||||
@@ -411,7 +426,7 @@ var sealBenchCmd = &cli.Command{
|
|||||||
|
|
||||||
fmt.Println(string(data))
|
fmt.Println(string(data))
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("----\nresults (v26) (%d)\n", sectorSize)
|
fmt.Printf("----\nresults (v27) (%d)\n", sectorSize)
|
||||||
if robench == "" {
|
if robench == "" {
|
||||||
fmt.Printf("seal: addPiece: %s (%s)\n", bo.SealingResults[0].AddPiece, bps(bo.SectorSize, bo.SealingResults[0].AddPiece)) // TODO: average across multiple sealings
|
fmt.Printf("seal: addPiece: %s (%s)\n", bo.SealingResults[0].AddPiece, bps(bo.SectorSize, bo.SealingResults[0].AddPiece)) // TODO: average across multiple sealings
|
||||||
fmt.Printf("seal: preCommit phase 1: %s (%s)\n", bo.SealingResults[0].PreCommit1, bps(bo.SectorSize, bo.SealingResults[0].PreCommit1))
|
fmt.Printf("seal: preCommit phase 1: %s (%s)\n", bo.SealingResults[0].PreCommit1, bps(bo.SectorSize, bo.SealingResults[0].PreCommit1))
|
||||||
@@ -426,10 +441,10 @@ var sealBenchCmd = &cli.Command{
|
|||||||
}
|
}
|
||||||
if !c.Bool("skip-commit2") {
|
if !c.Bool("skip-commit2") {
|
||||||
fmt.Printf("generate candidates: %s (%s)\n", bo.PostGenerateCandidates, bps(bo.SectorSize*abi.SectorSize(len(bo.SealingResults)), bo.PostGenerateCandidates))
|
fmt.Printf("generate candidates: %s (%s)\n", bo.PostGenerateCandidates, bps(bo.SectorSize*abi.SectorSize(len(bo.SealingResults)), bo.PostGenerateCandidates))
|
||||||
fmt.Printf("compute winnnig post proof (cold): %s\n", bo.PostWinningProofCold)
|
fmt.Printf("compute winning post proof (cold): %s\n", bo.PostWinningProofCold)
|
||||||
fmt.Printf("compute winnnig post proof (hot): %s\n", bo.PostWinningProofHot)
|
fmt.Printf("compute winning post proof (hot): %s\n", bo.PostWinningProofHot)
|
||||||
fmt.Printf("verify winnnig post proof (cold): %s\n", bo.VerifyWinningPostCold)
|
fmt.Printf("verify winning post proof (cold): %s\n", bo.VerifyWinningPostCold)
|
||||||
fmt.Printf("verify winnnig post proof (hot): %s\n\n", bo.VerifyWinningPostHot)
|
fmt.Printf("verify winning post proof (hot): %s\n\n", bo.VerifyWinningPostHot)
|
||||||
|
|
||||||
fmt.Printf("compute window post proof (cold): %s\n", bo.PostWindowProofCold)
|
fmt.Printf("compute window post proof (cold): %s\n", bo.PostWindowProofCold)
|
||||||
fmt.Printf("compute window post proof (hot): %s\n", bo.PostWindowProofHot)
|
fmt.Printf("compute window post proof (hot): %s\n", bo.PostWindowProofHot)
|
||||||
@@ -441,9 +456,23 @@ var sealBenchCmd = &cli.Command{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func runSeals(sb *ffiwrapper.Sealer, sbfs *basicfs.Provider, numSectors int, mid abi.ActorID, sectorSize abi.SectorSize, ticketPreimage []byte, saveC2inp string, skipc2, skipunseal bool) ([]SealingResult, []abi.SectorInfo, error) {
|
type ParCfg struct {
|
||||||
var sealTimings []SealingResult
|
PreCommit1 int
|
||||||
var sealedSectors []abi.SectorInfo
|
PreCommit2 int
|
||||||
|
Commit int
|
||||||
|
}
|
||||||
|
|
||||||
|
func runSeals(sb *ffiwrapper.Sealer, sbfs *basicfs.Provider, numSectors int, par ParCfg, mid abi.ActorID, sectorSize abi.SectorSize, ticketPreimage []byte, saveC2inp string, skipc2, skipunseal bool) ([]SealingResult, []abi.SectorInfo, error) {
|
||||||
|
var pieces []abi.PieceInfo
|
||||||
|
sealTimings := make([]SealingResult, numSectors)
|
||||||
|
sealedSectors := make([]abi.SectorInfo, numSectors)
|
||||||
|
|
||||||
|
preCommit2Sema := make(chan struct{}, par.PreCommit2)
|
||||||
|
commitSema := make(chan struct{}, par.Commit)
|
||||||
|
|
||||||
|
if numSectors%par.PreCommit1 != 0 {
|
||||||
|
return nil, nil, fmt.Errorf("parallelism factor must cleanly divide numSectors")
|
||||||
|
}
|
||||||
|
|
||||||
for i := abi.SectorNumber(1); i <= abi.SectorNumber(numSectors); i++ {
|
for i := abi.SectorNumber(1); i <= abi.SectorNumber(numSectors); i++ {
|
||||||
sid := abi.SectorID{
|
sid := abi.SectorID{
|
||||||
@@ -452,7 +481,7 @@ func runSeals(sb *ffiwrapper.Sealer, sbfs *basicfs.Provider, numSectors int, mid
|
|||||||
}
|
}
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
log.Info("Writing piece into sector...")
|
log.Infof("[%d] Writing piece into sector...", i)
|
||||||
|
|
||||||
r := rand.New(rand.NewSource(100 + int64(i)))
|
r := rand.New(rand.NewSource(100 + int64(i)))
|
||||||
|
|
||||||
@@ -461,129 +490,168 @@ func runSeals(sb *ffiwrapper.Sealer, sbfs *basicfs.Provider, numSectors int, mid
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
addpiece := time.Now()
|
pieces = append(pieces, pi)
|
||||||
|
|
||||||
trand := blake2b.Sum256(ticketPreimage)
|
sealTimings[i-1].AddPiece = time.Since(start)
|
||||||
ticket := abi.SealRandomness(trand[:])
|
}
|
||||||
|
|
||||||
log.Info("Running replication(1)...")
|
sectorsPerWorker := numSectors / par.PreCommit1
|
||||||
pieces := []abi.PieceInfo{pi}
|
|
||||||
pc1o, err := sb.SealPreCommit1(context.TODO(), sid, ticket, pieces)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, xerrors.Errorf("commit: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
precommit1 := time.Now()
|
errs := make(chan error, par.PreCommit1)
|
||||||
|
for wid := 0; wid < par.PreCommit1; wid++ {
|
||||||
|
go func(worker int) {
|
||||||
|
sealerr := func() error {
|
||||||
|
start := 1 + (worker * sectorsPerWorker)
|
||||||
|
end := start + sectorsPerWorker
|
||||||
|
for i := abi.SectorNumber(start); i < abi.SectorNumber(end); i++ {
|
||||||
|
ix := int(i - 1)
|
||||||
|
sid := abi.SectorID{
|
||||||
|
Miner: mid,
|
||||||
|
Number: i,
|
||||||
|
}
|
||||||
|
|
||||||
log.Info("Running replication(2)...")
|
start := time.Now()
|
||||||
cids, err := sb.SealPreCommit2(context.TODO(), sid, pc1o)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, xerrors.Errorf("commit: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
precommit2 := time.Now()
|
trand := blake2b.Sum256(ticketPreimage)
|
||||||
|
ticket := abi.SealRandomness(trand[:])
|
||||||
|
|
||||||
sealedSectors = append(sealedSectors, abi.SectorInfo{
|
log.Infof("[%d] Running replication(1)...", i)
|
||||||
RegisteredProof: sb.SealProofType(),
|
pieces := []abi.PieceInfo{pieces[ix]}
|
||||||
SectorNumber: i,
|
pc1o, err := sb.SealPreCommit1(context.TODO(), sid, ticket, pieces)
|
||||||
SealedCID: cids.Sealed,
|
if err != nil {
|
||||||
})
|
return xerrors.Errorf("commit: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
seed := lapi.SealSeed{
|
precommit1 := time.Now()
|
||||||
Epoch: 101,
|
|
||||||
Value: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 255},
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info("Generating PoRep for sector (1)")
|
preCommit2Sema <- struct{}{}
|
||||||
c1o, err := sb.SealCommit1(context.TODO(), sid, ticket, seed.Value, pieces, cids)
|
pc2Start := time.Now()
|
||||||
|
log.Infof("[%d] Running replication(2)...", i)
|
||||||
|
cids, err := sb.SealPreCommit2(context.TODO(), sid, pc1o)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("commit: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
precommit2 := time.Now()
|
||||||
|
<-preCommit2Sema
|
||||||
|
|
||||||
|
sealedSectors[ix] = abi.SectorInfo{
|
||||||
|
SealProof: sb.SealProofType(),
|
||||||
|
SectorNumber: i,
|
||||||
|
SealedCID: cids.Sealed,
|
||||||
|
}
|
||||||
|
|
||||||
|
seed := lapi.SealSeed{
|
||||||
|
Epoch: 101,
|
||||||
|
Value: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 255},
|
||||||
|
}
|
||||||
|
|
||||||
|
commitSema <- struct{}{}
|
||||||
|
commitStart := time.Now()
|
||||||
|
log.Infof("[%d] Generating PoRep for sector (1)", i)
|
||||||
|
c1o, err := sb.SealCommit1(context.TODO(), sid, ticket, seed.Value, pieces, cids)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sealcommit1 := time.Now()
|
||||||
|
|
||||||
|
log.Infof("[%d] Generating PoRep for sector (2)", i)
|
||||||
|
|
||||||
|
if saveC2inp != "" {
|
||||||
|
c2in := Commit2In{
|
||||||
|
SectorNum: int64(i),
|
||||||
|
Phase1Out: c1o,
|
||||||
|
SectorSize: uint64(sectorSize),
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := json.Marshal(&c2in)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ioutil.WriteFile(saveC2inp, b, 0664); err != nil {
|
||||||
|
log.Warnf("%+v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var proof storage.Proof
|
||||||
|
if !skipc2 {
|
||||||
|
proof, err = sb.SealCommit2(context.TODO(), sid, c1o)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sealcommit2 := time.Now()
|
||||||
|
<-commitSema
|
||||||
|
|
||||||
|
if !skipc2 {
|
||||||
|
svi := abi.SealVerifyInfo{
|
||||||
|
SectorID: abi.SectorID{Miner: mid, Number: i},
|
||||||
|
SealedCID: cids.Sealed,
|
||||||
|
SealProof: sb.SealProofType(),
|
||||||
|
Proof: proof,
|
||||||
|
DealIDs: nil,
|
||||||
|
Randomness: ticket,
|
||||||
|
InteractiveRandomness: seed.Value,
|
||||||
|
UnsealedCID: cids.Unsealed,
|
||||||
|
}
|
||||||
|
|
||||||
|
ok, err := ffiwrapper.ProofVerifier.VerifySeal(svi)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return xerrors.Errorf("porep proof for sector %d was invalid", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
verifySeal := time.Now()
|
||||||
|
|
||||||
|
if !skipunseal {
|
||||||
|
log.Infof("[%d] Unsealing sector", i)
|
||||||
|
{
|
||||||
|
p, done, err := sbfs.AcquireSector(context.TODO(), abi.SectorID{Miner: mid, Number: 1}, stores.FTUnsealed, stores.FTNone, true)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("acquire unsealed sector for removing: %w", err)
|
||||||
|
}
|
||||||
|
done()
|
||||||
|
|
||||||
|
if err := os.Remove(p.Unsealed); err != nil {
|
||||||
|
return xerrors.Errorf("removing unsealed sector: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err := sb.UnsealPiece(context.TODO(), abi.SectorID{Miner: mid, Number: 1}, 0, abi.PaddedPieceSize(sectorSize).Unpadded(), ticket, cids.Unsealed)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unseal := time.Now()
|
||||||
|
|
||||||
|
sealTimings[ix].PreCommit1 = precommit1.Sub(start)
|
||||||
|
sealTimings[ix].PreCommit2 = precommit2.Sub(pc2Start)
|
||||||
|
sealTimings[ix].Commit1 = sealcommit1.Sub(commitStart)
|
||||||
|
sealTimings[ix].Commit2 = sealcommit2.Sub(sealcommit1)
|
||||||
|
sealTimings[ix].Verify = verifySeal.Sub(sealcommit2)
|
||||||
|
sealTimings[ix].Unseal = unseal.Sub(verifySeal)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}()
|
||||||
|
if sealerr != nil {
|
||||||
|
errs <- sealerr
|
||||||
|
return
|
||||||
|
}
|
||||||
|
errs <- nil
|
||||||
|
}(wid)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < par.PreCommit1; i++ {
|
||||||
|
err := <-errs
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
sealcommit1 := time.Now()
|
|
||||||
|
|
||||||
log.Info("Generating PoRep for sector (2)")
|
|
||||||
|
|
||||||
if saveC2inp != "" {
|
|
||||||
c2in := Commit2In{
|
|
||||||
SectorNum: int64(i),
|
|
||||||
Phase1Out: c1o,
|
|
||||||
SectorSize: uint64(sectorSize),
|
|
||||||
}
|
|
||||||
|
|
||||||
b, err := json.Marshal(&c2in)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := ioutil.WriteFile(saveC2inp, b, 0664); err != nil {
|
|
||||||
log.Warnf("%+v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var proof storage.Proof
|
|
||||||
if !skipc2 {
|
|
||||||
proof, err = sb.SealCommit2(context.TODO(), sid, c1o)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sealcommit2 := time.Now()
|
|
||||||
|
|
||||||
if !skipc2 {
|
|
||||||
svi := abi.SealVerifyInfo{
|
|
||||||
SectorID: abi.SectorID{Miner: mid, Number: i},
|
|
||||||
SealedCID: cids.Sealed,
|
|
||||||
RegisteredProof: sb.SealProofType(),
|
|
||||||
Proof: proof,
|
|
||||||
DealIDs: nil,
|
|
||||||
Randomness: ticket,
|
|
||||||
InteractiveRandomness: seed.Value,
|
|
||||||
UnsealedCID: cids.Unsealed,
|
|
||||||
}
|
|
||||||
|
|
||||||
ok, err := ffiwrapper.ProofVerifier.VerifySeal(svi)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
return nil, nil, xerrors.Errorf("porep proof for sector %d was invalid", i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
verifySeal := time.Now()
|
|
||||||
|
|
||||||
if !skipunseal {
|
|
||||||
log.Info("Unsealing sector")
|
|
||||||
{
|
|
||||||
p, done, err := sbfs.AcquireSector(context.TODO(), abi.SectorID{Miner: mid, Number: 1}, stores.FTUnsealed, stores.FTNone, true)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, xerrors.Errorf("acquire unsealed sector for removing: %w", err)
|
|
||||||
}
|
|
||||||
done()
|
|
||||||
|
|
||||||
if err := os.Remove(p.Unsealed); err != nil {
|
|
||||||
return nil, nil, xerrors.Errorf("removing unsealed sector: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err := sb.UnsealPiece(context.TODO(), abi.SectorID{Miner: mid, Number: 1}, 0, abi.UnpaddedPieceSize(sectorSize), ticket, cids.Unsealed)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unseal := time.Now()
|
|
||||||
|
|
||||||
sealTimings = append(sealTimings, SealingResult{
|
|
||||||
AddPiece: addpiece.Sub(start),
|
|
||||||
PreCommit1: precommit1.Sub(addpiece),
|
|
||||||
PreCommit2: precommit2.Sub(precommit1),
|
|
||||||
Commit1: sealcommit1.Sub(precommit2),
|
|
||||||
Commit2: sealcommit2.Sub(sealcommit1),
|
|
||||||
Verify: verifySeal.Sub(sealcommit2),
|
|
||||||
Unseal: unseal.Sub(verifySeal),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return sealTimings, sealedSectors, nil
|
return sealTimings, sealedSectors, nil
|
||||||
@@ -597,6 +665,11 @@ var proveCmd = &cli.Command{
|
|||||||
Name: "no-gpu",
|
Name: "no-gpu",
|
||||||
Usage: "disable gpu usage for the benchmark run",
|
Usage: "disable gpu usage for the benchmark run",
|
||||||
},
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "miner-addr",
|
||||||
|
Usage: "pass miner address (only necessary if using existing sectorbuilder)",
|
||||||
|
Value: "t01000",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
if c.Bool("no-gpu") {
|
if c.Bool("no-gpu") {
|
||||||
@@ -620,7 +693,7 @@ var proveCmd = &cli.Command{
|
|||||||
return xerrors.Errorf("unmarshalling input file: %w", err)
|
return xerrors.Errorf("unmarshalling input file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := paramfetch.GetParams(build.ParametersJSON(), c2in.SectorSize); err != nil {
|
if err := paramfetch.GetParams(lcli.ReqContext(c), build.ParametersJSON(), c2in.SectorSize); err != nil {
|
||||||
return xerrors.Errorf("getting params: %w", err)
|
return xerrors.Errorf("getting params: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -658,7 +731,7 @@ var proveCmd = &cli.Command{
|
|||||||
|
|
||||||
fmt.Printf("proof: %x\n", proof)
|
fmt.Printf("proof: %x\n", proof)
|
||||||
|
|
||||||
fmt.Printf("----\nresults (v23) (%d)\n", c2in.SectorSize)
|
fmt.Printf("----\nresults (v27) (%d)\n", c2in.SectorSize)
|
||||||
dur := sealCommit2.Sub(start)
|
dur := sealCommit2.Sub(start)
|
||||||
|
|
||||||
fmt.Printf("seal: commit phase 2: %s (%s)\n", dur, bps(abi.SectorSize(c2in.SectorSize), dur))
|
fmt.Printf("seal: commit phase 2: %s (%s)\n", dur, bps(abi.SectorSize(c2in.SectorSize), dur))
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMeanVar(t *testing.T) {
|
||||||
|
N := 16
|
||||||
|
ss := make([]*meanVar, N)
|
||||||
|
rng := rand.New(rand.NewSource(1))
|
||||||
|
for i := 0; i < N; i++ {
|
||||||
|
ss[i] = &meanVar{}
|
||||||
|
maxJ := rng.Intn(1000)
|
||||||
|
for j := 0; j < maxJ; j++ {
|
||||||
|
ss[i].AddPoint(rng.NormFloat64()*5 + 500)
|
||||||
|
}
|
||||||
|
t.Logf("mean: %f, stddev: %f, count %f", ss[i].mean, ss[i].Stddev(), ss[i].n)
|
||||||
|
}
|
||||||
|
out := &meanVar{}
|
||||||
|
for i := 0; i < N; i++ {
|
||||||
|
out.Combine(ss[i])
|
||||||
|
t.Logf("combine: mean: %f, stddev: %f", out.mean, out.Stddev())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCovar(t *testing.T) {
|
||||||
|
N := 16
|
||||||
|
ss := make([]*covar, N)
|
||||||
|
rng := rand.New(rand.NewSource(1))
|
||||||
|
for i := 0; i < N; i++ {
|
||||||
|
ss[i] = &covar{}
|
||||||
|
maxJ := rng.Intn(1000) + 500
|
||||||
|
for j := 0; j < maxJ; j++ {
|
||||||
|
x := rng.NormFloat64()*5 + 500
|
||||||
|
ss[i].AddPoint(x, x*2-1000)
|
||||||
|
}
|
||||||
|
t.Logf("corell: %f, y = %f*x+%f @%.0f", ss[i].Correl(), ss[i].A(), ss[i].B(), ss[i].n)
|
||||||
|
t.Logf("\txVar: %f yVar: %f covar: %f", ss[i].StddevX(), ss[i].StddevY(), ss[i].Covariance())
|
||||||
|
}
|
||||||
|
out := &covar{}
|
||||||
|
for i := 0; i < N; i++ {
|
||||||
|
out.Combine(ss[i])
|
||||||
|
t.Logf("combine: corell: %f, y = %f*x+%f", out.Correl(), out.A(), out.B())
|
||||||
|
t.Logf("\txVar: %f yVar: %f covar: %f", out.StddevX(), out.StddevY(), out.Covariance())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,7 +21,7 @@ func subBlocks(ctx context.Context, api aapi.FullNode, st *storage) {
|
|||||||
bh.Cid(): bh,
|
bh.Cid(): bh,
|
||||||
}, false)
|
}, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//log.Errorf("%+v", err)
|
log.Errorf("%+v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
"gopkg.in/urfave/cli.v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var dotCmd = &cli.Command{
|
var dotCmd = &cli.Command{
|
||||||
@@ -20,7 +20,13 @@ var dotCmd = &cli.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
minH, err := strconv.ParseInt(cctx.Args().Get(0), 10, 32)
|
minH, err := strconv.ParseInt(cctx.Args().Get(0), 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
tosee, err := strconv.ParseInt(cctx.Args().Get(1), 10, 32)
|
tosee, err := strconv.ParseInt(cctx.Args().Get(1), 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
maxH := minH + tosee
|
maxH := minH + tosee
|
||||||
|
|
||||||
res, err := st.db.Query(`select block, parent, b.miner, b.height, p.height from block_parents
|
res, err := st.db.Query(`select block, parent, b.miner, b.height, p.height from block_parents
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user