From 061a990eb8e566bbfbb56379882b077a13493bfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Fri, 9 Sep 2022 14:38:23 +0200 Subject: [PATCH] sector import: RemoteSealingDoneEndpoint --- api/api_storage.go | 21 +++++- build/openrpc/miner.json.gz | Bin 15813 -> 15826 bytes documentation/en/api-v0-methods-miner.md | 3 +- itests/kit/node_miner.go | 2 +- itests/sector_import_full_test.go | 78 ++++++++++++++++++++--- itests/sector_import_simple_test.go | 27 +++++++- storage/pipeline/cbor_gen.go | 36 ++++++++++- storage/pipeline/fsm.go | 61 ++++++++++++++++-- storage/pipeline/fsm_events.go | 3 + storage/pipeline/receive.go | 9 +++ storage/pipeline/types.go | 13 ++-- 11 files changed, 226 insertions(+), 27 deletions(-) diff --git a/api/api_storage.go b/api/api_storage.go index 6273c4881..5d7455340 100644 --- a/api/api_storage.go +++ b/api/api_storage.go @@ -573,12 +573,17 @@ type RemoteSectorMeta struct { // SEALING SERVICE HOOKS // URL - // todo better doc + // RemoteCommit1Endpoint is an URL of POST endpoint which lotus will call requesting Commit1 (seal_commit_phase1) + // request body will be json-serialized RemoteCommit1Params struct RemoteCommit1Endpoint string + // RemoteCommit2Endpoint is an URL of POST endpoint which lotus will call requesting Commit2 (seal_commit_phase2) + // request body will be json-serialized RemoteCommit2Params struct RemoteCommit2Endpoint string - // todo OnDone / OnStateChange + // RemoteSealingDoneEndpoint is called after the sector exists the sealing pipeline + // request body will be json-serialized RemoteSealingDoneParams struct + RemoteSealingDoneEndpoint string } type RemoteCommit1Params struct { @@ -597,3 +602,15 @@ type RemoteCommit2Params struct { // todo spec better Commit1Out storiface.Commit1Out } + +type RemoteSealingDoneParams struct { + // Successful is true if the sector has entered state considered as "successfully sealed" + Successful bool + + // State is the state the sector has entered + // For example "Proving" / "Removing" + State string + + // Optional commit message CID + CommitMessage *cid.Cid +} diff --git a/build/openrpc/miner.json.gz b/build/openrpc/miner.json.gz index 3d42364ddb4334b44a3ef885e0d3e628097916d1..f2bd95d2fb4f845af7ee46ac47065bd04a687dad 100644 GIT binary patch literal 15826 zcmV;@JuSi?iwFP!00000|LnbcbK5r7IQ&&GeCM4_JF=s@Ezj&9iJhe0I;|huX`g4~ z%oZXc32O>qNywLE{M~;8fOmo}egbg-ube(GDPicI?H|kk{sdk@`EuWH)C0(MsrwW7c1^AsUI1_ZlrZEH zXeY1%|NJK)*p|(%nTy!QCE#a*?$Qu{>VbEz`x|AK8^@t8Ll*z!k^js8DyNHAPXDKC z@_0@D`s**FXLy_S8oCe0kzw=<2fA=A2f1^}?sOJ;$XSuh%xG-Pd!Q&R?&g$B_FP zI{3BY())-1ED_mX(*N&lG@H$g$H!hV)gDu_z{|$8E5WEKIMGCxer4+dDo(VkO~WDH zTcPCQIZnSVr{ZtMxr>hJdW{*MUYFWQ(k^&)h1@kJkRj#U69nz^&D_S`O8p*taBidD z?+9|=L))H1^CsX2|J|R|y-B}(EMqq(_UKz0{ci?lXf57o@NB@ckKqI8y6}PjR*kMb z;L54_7POmFY9mNuEz=XFYMNc<*6_^|LQ9|@UzGG5_Xqs~>3NC7zwuX8Uvx$=6mqi% zoB>E{YVZoq@qYAOsW6S27TE&{nAJsTVjLXr# z*{tWt&4Bq$JOTzK~u+K`wH zI5Y()mrdt*|BBuq@@7ppgqu7jw)T&)Rmz{K4hopmhgh9Evt!6-(KI^Hw&|S*7zKC! z8!-1@EnK<=Yd&KD@@{w|dMAEL#=It%4l?oL0YEV;0D9os=wBNNaEpy?2Qc@+)e3t+ z?zey(4kzt3@;tai;P~|9nm}R!iy{vY%D^4O3@oS{HbM8u-0)StCT)qED z8lNsQct_7mWQ!nV!oaD82*V4kkTb`aFNfnI4-v*!#6$LCPqvw3vXo50msl=6vH%XD z?SoUsMbv`2Yh;1>1AyQUxz+9g2#%?ROz`S%h0PVf#KL^UV%0Y`!zO>b=RorYSz#}H z?tTKC5Fq%-TdknC+E0qUZ^moB-f;0SoPUKTf}=anT1_8Da5QD}k#~dE&VT9s-_GWN zuATqR*9-Kp7>yTrw0W3rHfTJ&9UG4^sp&BnljV0VHAh3W)I44x^XA;8x7%Bo1U;Mw};zWB=!v1HkX_#qFfWqa3wE*UpBa6Ud;-gwfJF2@pk! z=M!jiY7^}tR5HV`zwVvvxzq#qyXi7$KUEm8?huugZ^mPGsL&YQZ2P%^j37*#=9@v zQ>27k&mTlRRrNiK!^yZ%90q1vZDA+?EtSFpds;M%+pD=Rb|aiq%om8Ku094MI||Y|+jb^am{% z8e`P}Qetp>gP7JGfyyjV2-O1NrQuOX%B<)EF0;g6Zyy+cYy2Ov`~SXtyE4hYR_K5J z`A?(1c!~9*BVOWYd^6U_!UFR-CeVF&M@(vQiNNKhho6xt_$ zVq(!dKJQJ8ln6?mrLw_mHpE5N z*Mr498881k8I7zF9go=GWatdBbAP{bZ_U*$l2Ywyj)BVPR3X?)KhT=(69g?A6J#8X z`Cb&dOpI1i>lB(z#!d{R8GSX@|66!tif}2dn zk+g*BtCws~I$9=!Ml8fe$L=caKoQ~OuY#5mjIEMx@K4GKE*DnIpbr+lT6B@h!JQs; zKtc7!@NAYtr3k7QW?LLgb8HJ2L5AK!^Je4JGb>^M@+=DfI8T}eO3NSyL~RsQQ1(fL z@`ElCotol@2MDzgn9FCBSjYuzg@7j_DloDDpMJn6aUWc*&@~BzCIn%4fUO`CpNM7I zlYtu81MY?pOqL=5gTKEfXTM*4y8O@EH^;wzI{(kxH<$1JbN=S)7l6nub}3o&z4I+} zu{b{U5CeDTeLcYNW;C+Ag}1`f;Q^d~ z9pmwIIpBU3D~_!Bj- z@qCz>W7wV%_!2Yj!T_sm?Dh|!!)J%ZY<@~G!_dZGCFL~Y`4p_$nmq?zQzf5|X1>19 zLj{MwJpc*Vkm!L0JlA(8?PrpcmTRcgr3G12d~9;fFb*VV+wC6wyw$P?*N(%-(vP4kVh;uyd0O_VzS%^ zr^I6jT0V3EJO=oh2n%X~U5^1ML=Li&QL+olr!PJu0b$TZIPUqwHIbil3@{U`8AsYh zHiG_3A3pZL#zTvZEy8u7y9OIa8jL11R|q7Ros$pxd&3tewf4NBPf;i$8{`SX2`OTQ z)*(&U4=QR{Kx}&eFCyCJD9V)pf`KkMCcmLO;PF59ugNI`bDNqs9@r3u?eqjKFu~qR z&|YVCe!uEyFwDu*3FPb<_Lv}$dKtP|Fj`hhGOj$!z+ly$7Dg> zwPYSRryB;KZ3lAkhR{30nO(?;$XW%z6Z-+cTZnD3g``C6ZKIti=jSzaZxHh$E!4V^ ztBkx+w|Qa%mkTT7$cRMPn_#YtoiTSMj#_bwFU!^)jB@gfLN=lFX5)w$sD|Pt1}M+U z4RV0$3!7LcPa$rSV=6a^6Zqwe9be=K9~Yk|==+hD_!bdv&b6n~yEK|-Orz=KdMDSn zB-h6|nNR`YTp*L)BDc8%BMzvs_aY9gE!RZ~!Ezy;Kmsy`)(#UnqON=apxCS>oEG&q zbAqBdoSY4v-{C{Fl>?`X*i(T;k8gMbT_TKAG0oks@B3!pNls2lM5WUE(*_5}Ahp24 zF=*}aa1uowCXS<#b(O6l*+AQVkp3#m|4ROnW|rf}{dauyUGvd2CmG=cLEAf~#KRVH ze_t$YOwdK(+7mD9F;yv8wRdGssa?3kDTS-%HMtN~SWagETPY^xXHq^#dgZPX??Fza zs%nvZYHXKu<3QUZ+&I)Nl5Gn4j%c5TXb*Ejppr{Owjyv9P}?9|1=y|7ts4D~aG!>7 zXL;d0*)?ie*k)k1MzmWOwJOv*f_)N#9rp7ARpKl3iQFPr#4EN-v}(955Uv{VHi$QO z2ps`G4FL~w3iu{g>5r|DuL^1l#H#|k4bsg)za!kIA>2`3Oa@?Mn3`hf^4d5d&5&1|x>$R@n>gnj%+!WO9tIk66!l*B_H@ybnapkog>$OY4l^z zkEty}r#U9#g+wIvIDTgD*N@J2e+E7F$+0*yrqHmVw~9Y%P}L>AR8`Vx{pqb*X+Ap} zRUt%+qLb|DFL2dP>es@G5vOJ{s!x=aQB)9IRTy!i(@FtW(tp)nlk8fMd6UFca!Umo z&GL_4-J&!*YJC-B$vQ@2D3~fn4DE)almKptP4uHu>N80W`W=hB92OZC zg=<|R)}pss1ug%|kFan+DMx5Jt*f(v3fryIe&?9pWyf?UGtS1NaZaS1sIZLOH-yj) zG0_{lfy*KXmhylrS3=|fX(}J`aZ^i%JTzpL5HD6@%=HTmiJBqMwq-Ro1T5aZd4ZuH zj#4K%(Nw7wQHBH6pi&N}v=ELiwQ^uBQ>u?&z7A8N5Kw87LPa4P2nf0p#0l=82V7(# ze2c8!HSt7Itp{L20xWt*Yzi%anHN-G?4n1%|LD<9!kmpq)0|Kb8A*5yiHYnJ$l#R= ziMLRYosO8v1C}RiEXW}9+w2F8PftW#xr30qFa92tZ8`J0Z7P)thEsm^bS_e+c*L1X zl#dO@AC`^xYe0n0PfrAQQMN*^n3dL~QqJ^m?Jk?qR<5$~2}Lged@wv2{YvSdAHLpy z{q^7fcZ+`cU*>$6zVX~o|9WfwdH>7X_m{(8ym$1&)xG=i?Dp6HWsBN@;yZeI^A9Kc z4sxPl{3z-ebDm(hB-CTrthXB|gqSAaq4odz{LT1HQfI3B6Gg^W z_)^|pV_jkKWxwAa?1_J_`u!vE&%ceH;YW=ZH#(zBiNzURX8X|q@%ZKO%j09uh_g#3 zZH%)cUyqJAI^O7bBh4EXueevKnR<85B{-(aeS0T*`6MyQQ`CEn@mGG$*Lc=diis*9 z9OJ5LiBJjd$tL;4c}ev)WFW=xV?3lThU;@fmCMb;k7`jvoN=nALnT;JF&@cF^$-*6 zr+}H@!1nKRl(Ofk`_0Q6+jx3B7gsG++Pm^n%<>OHZK1`q3DFl@{>-GNXFpfjtN1K# zMpPu+q{*Q*rZlQq%cc{@ojC5qaVL&Das1@sSe1kPJ$qsga}utkv+x6AZ@ilZj#mjl zom~90e;uE^4{84rFG(0M_{O^_ce6_1EqYZ$Y`2n9Tr%FQtFW}aj@OX46eTRMiTr9C zL2zdL*+)z=B||>K`|LBm#_{SPTrPSHuAQhN$i0I(Qb8dO^!IO+@4>lf!%G6?%zZPi z1Ro81hA57uy8OQ4&eb1km0Lu7RCOd_ayGQSNX)6`7xl_qh=r_N*+Q<2mfna~Sxajq zDXh8HOb||m1(u{$>jwLtPoQm8s`!qz#JHc6R27QNFr}`sx`;!{(Hr5Vo4#b!RTgp3 z?P`q_(%VrVieYDUhPsiCq6iAsynSGSQustX#F;Eo6X)<@jR+Gna0_keT1`DXC8mp@ zhlI?pCc!h{waNqKb+1=jC_d_{5;QSEHKp7O5fQ_jj2X!zetAd)?b?+vRe)M4hp7VG zPM}f-*{(3=OAl@A3S;h^WE$lpDoGwa!(JjLrb(Dl23G#%$x$QU<56zGWT2N^YMSYy zQn{`C5pAj7mI7hrU6-m>TIo*RsrV0cDqg$RXLoqe9UgRt2Tyi*@M24Ojwd;}jxohr zJI65vqhW3C6tt~W=+0u?)#>i)ba!>SyE@%no$jtq_jjkZ8yM$myu2Nst}gmW+cOv=xRze#_2iXvt`h&nt!m^unn<##VbX z`o^-}Z;0gypk!m)J>z^cx3Ra1JqcnTYC2!S1*!SHuQtSq8z+Es$oSmv3yHPnxV>I@ zZ0!t&BjHA3(1HvWx5`*wJ>xy}qVvpvm~x#`V%9E@hum8(p~Zqni1! zJQei0TbV-AAdqR{#?h>2oRT@+5bOBOMS6+qo8bv&s%mrQtcuEI7TN6?C<@uK`%xol zI;-wjgSM_OC&lHe=}obARczvvrC6aNe`iv5sTu@vQtB;B?swe=vD+Yi2OGqciBoY+ zVs=Z_Z+*>O#pMzz-YwHkQh{rI;aeEh&`Me@S`p$&rP}@uJLWOachV<}kR8wV`2idT z2Zhz1_$Ii8+ZytK<+%&e!GeL5({mi?+}Ys!4N7~g=|RYhcS{b0Qv4OJ1f6g6 zoC@&4rqF6PQi1PrxCpa_5aWO^;9cIKd--0^ay3pz7&=) zUm1UYAS*WpX(V}m0zbVgNf&2m3C)LdmojQnf9qX;+xea4x27jVYuA>X^2%E>&5@?p zrE0uNQczVi3!gp&yxI0A5CB#D3zDrH0p*c*|h9^;;9WY6;y%P|qs_hB?=AOP;uFT7vH~uLPf9cs`Hb{#(2}B}^DQ zsRttf=Xn2k1u+qOy&iDJ;?X&@EM$dy-5zizs^_JWu!TWPzS}``D&%ZD z85I`ax@@gJ-(_iiKA}`pRp@jSL3x3`8X6&m@YW5=t_0spFTvM|oU`#{oL5x~6HJzG z`Rdn_GvVhs#XqGDbA_Et#0rnILqP46`i$eXo%){fk!7Vy>aC7AImVV3gldY|`S8~- z2rpO6I4VCLeMx5=lW9GdFd9}qh}Jy8Y<=umDNNU4kE)z6Ojgi#mm`yUlibh?99 z=vskw=W_YcTrLVi%nBf78!a)^dQglIW@pqCxst(6e|8YS$nBv-u5YjP;GD{rs?`r9 zNRPE%XiCM@srtbWv2|!8H1vg?vQG|j>V|}3I0`9lq=P~*)wEFfnU)?3Tequ;;<$IZ z=ttH?`OJ{lN^6(BgPA%{7^T?d54_kQuE}9emZ_AjXV_!M*y5~GFM2BrCNHxzEWlr; zM&iH)4uB5kGzS>+7$(a~VWcW%j-#wR*p9u_*)jO#rUw0fzh{KS(<&P6 zQO&AS^H{%>%nLJMr-Pj6@C!j*Z!8&%P>XSrAoBbod`pQJ&_w&k(6;>ma1jd;xkj83 z_&M3`on*4y6YgZ+O^>!SBPkC6Z^>Jdo*hm8xeT+Wb2v$sCNTO3^8b5^e+B)D_=l|a%xpP?2K6=HIVw^Tjq5a6_KyUi^j(nV%8(4oVeqyninP9TG- zZH~SQ^&vcm2KBpcM}bD;DA%76vVT(d2DuVKYxz!{UhVX1r&l|@+UeCD)~lnOJRM(~ z&^uyNXf<%{r~p;cvh{RoqQ90@YkCY%a`ADeMLR88rbRn>-pO-co{w{qW~2yvkC;e4 zt1HIE_uH4=qMLSvc7Smwt2{h{h z0$Hx=wk6q~Gont`ce1{d^_{HWC0T!vlckrGWR3kSNkC60-P`oDWX90R^G=?3^1PGh zyClyKb8_CK2>XBtav}3Y*sti}y-U}k7IuBno(psPQa-oqb_9OW$U52I$^K6Ecd~z% zWdAHDAx%oNkMtJ#QoMn*k3reKe2;b3jzmvl-^uV!hIcZ&li@og!w>p7xrkDJoxAil z=~m7P9DP}?fL2MSM-P1Dv7DVw)6i*yob=p0p`7K4COU1{Os7d8g8kamXv1x3v|*>wI*qo|8ZE|A zdUf&N-fm$-+L{(O>Z) zbXu#^T05h)p5|V*PM37LL`Rp53bV{Fkd2^+F%-#4tu?xFQ$i@YR@ZWqys`)3#T`8=daEx)0= zOKH@#RzLkWbQfBR&r_WwF{o#vky;LnWEzJFo1a*@bjTn@gTC8C>Mhtao5u35j+R@BO?7K+KP9^VzO73KM zC&PUiKFF)du^|kv(dB0DJ$Qn3YRT|46!k^J@|&3m-AzoF>iZ z;4dySqncYEp?iavm#)U}oF1qh<+x!^#Q=Y9-^{7YYB5_JfUd1nU=qc_HMNFPsBu&} zBd9ZiwrvD;8vbm2ILgV@_IdIGtwouQzck^5oBEgRT8fpL7II0$xi3D2-#j zAo4%BG*`%yUx{V9MVtj)AE|{)*T9o4frA}nV}e?{%Qc)Uz4IR}p|ln4TrOs+Y3`0~ z&&G%2oV3_DVV+>PY{If3kUVysQ)>SNUSZBgT%CSoLwE_cc zvv#Ukt~l+h+Rxr)*t z5+>^>XX!$#o*Od@CXd6D*?Xi8DDs@ zfD_|rG9C@(FODhopv^xPeH=?4N;{DP5fK~>`n=0Okc$@>S-k6DCXQ{42s4h1MSn0H zjg6jh?$TRqAvgZ)49<})hkMDO%icNETye02{-9^PBUbW(FTT!QY@&1I`Y(-s4Eiy( zZOD+zF%d5$BB{rZa-J@IV^@SAl=lDFGk!(LiDC`}5mfVK1#6|_7fP>WmBS-{_DeoW zIg?bARTV-sXF5al*S~5fahk3cFcPC(9sDAit&F0A9;?ELlcWx|YWAqwYm%G8GsR#d zrf@=LnW+M)RwI~dQ=&pO$->#;^%4^HX~K$Bc5d9T$taH0%PJoHS5&IHcCS*l{r2`qKl=H;*`#%@O zyTs(Z7(!JuA=Z1l=Z?v~6jPU}b0DhOo8dLu z51N#7cMj|VK2LN|gU$0tQ^fFjcrFo>QFO?E3pjqlrh$Pskx_A~*O;jjBhRd7`t5ey zg42HZzuMlx9c8OQPOd;m0Ak^h4V$?4<6zoipb+48xh9Tx39CdHh5RAdLY}h$g6`~x zJ>Nm@bICQigP3`ObJo;Fz(UaWz#J|353WNQbeR{Nk9W+p+srh~3EGw<@)5c>@2T7T z&^if7_t-kTh@6YLDmPm*-A`-jXsa3Mr@&V4qXjdG*ECG|3M89~78ssg^a2wd@Fr?6ovzfj7h7y+|1jpx*?n5rYjib+#-r!5mcoQHTJ~<_yJQV)=4c#;0+o*IX6N6gyu+Q(l z>Sq#99S=%01=ad^VMju?N_xtJ_V6_*dC9R(GkR2D56bZfcP z@gfI?L#{a3X)ofuA%c; zF5#CsW($mLYyT}~@A)5E3N_wEfkG|nr=E6Ajje>G5@=@63X*y@#%o?{fLH_>K=J^nhysqa0W0VMliD`6guhWj@c;)1*JvMHA_f-J zl>x|{2Kj&KEplCKA>hFUVh_MvA@j!Dzb1b`8(Y9!K^K~g!&&%%jsV>I+5>O){@nxp zy;%?Zrw8`FUo~6o#i=D%giT&%iML-ys&hF#nM6D+jMIwv`-3(v_Bn{cP!Gul6 zKY>?GEEL&WfrZklSrU$|*srX{QB!~l>GhY%Klv-!ip#qB1F+BnZfpj``pb-oz)1jX zdWSr=2X7&^;oL?k079IuP(of`llO8T!dz@hLy8jc7pE8AKgz7{3l*S}9Jl7X9}nBi z5Gyx1cTOMdqilkx+OI2`d z*hC%QI_H@B!L4D_XNYgjOkH7!tEzSFDA(tRS?z*MpH)r`3M11(>S`Wmng-QQsA(GN zHls}yBhZpa#1@8^rz)cG{7=w{2K*}~R(glQNp_7q2G@?9@hcaaDBG%_ zQ1l68FrKA+M$Jehe7ZQx0{aC)3%OF9{)!&54T6bC_4Oz_yL`H?j-k0iTklD#G+#)( zBbGz45Thvo@n*xaW_}U16G~8C)5=x8g}|!1b@WABozG&FT<>$AQ@$C(Il=#!V*=fW zcf_P(d&ODTL(_3=D;mK_5I}{A3MnDBS+4N8ARfiW-KQU|Owx2+Sf6}VB?JU9YXMF2 zUN<2b$=6MZ)HOB7B-E42W0iYpKtg-z>{xy6R%?EOJwUzD#m)Jy2v1jprz^tK72#3# z7y1_}%t?Lv)+OzNa_&VUGr9HM?%{!IQ&^n~Q(N!KqI&CRB*|U3UR-->ORgf~oDF&f z_{mLrZAMjcC>U%<)c=X<&(NBMBD);Bk<&HA#(8h;FJN2A`zFukh{hNGEs?v zl09<;G3kN36*gDEgyfpc5wIxnqhMq|SHVa7;sEa!lO=$}0)$2Y`7;~eqFAkF+Xg1w zcnCyN5jcoIn~T79%PH@6LVU;1XOsT8FdO}{^?J^nShCUC>(8ZylJ_#xc%VwTwKcFg%>G3Q}n z3Vuk7O%tk;fYeC}KbzRvKgJsQq)BKkU0ta}Q;SjabE6_}QE6^ejC-FbJ1Us(%(BK_ zl(4Mwgdz#-7+b*Qq|b4drF87Yo@_H0)`brPT9%7E4_N?*(1hy^3p;;}EHHln5d48$ zPZWfO;Fwy-1h1s?4HFBSe#-88V>4{>w|fpWZ;%!C!ddqx;e3POBX6~W-fBN7QTU|S zPFmejKA#mPmWQO=JRvC!s-1+SG}LV-Bq>IqB?ih9k^)ar#Ohs2QkRm{khKSc!klRD z4A;IZKK#C%iGzB=WsEGqX>zY`t5@gX0B1GZ3Jjoa^Ns2e+gYF3^n1Fpra?@n%JoFH>!ezVoo3j zx(u5e8@i$Mr=?wFViNUuCCvRxaZB2ot4aAC=kF%xj|vlWy$iHx#PR(5(&CMrTA_`s z3$)PSZ4OeeSYr%s9lrK)-%9aqHI_vs6_d?$l6q%{{eC}oW#s9JusY+{Mvf0B2h)Bp z%+?jZAIoYl)`{@1e&3{SV1NA}U7Z3O-!pHI3qzSat{gUvxLZP~achQu+xsb5Pz{ck z-IU%PFRrJr!RO&9itC+yKur3RB{p;cAXwtt@X~lNe*mW^KaeAMNAKH+h#}{;-3oWK zN0MmPQxr)k%2LnGLKdfeQI>dDJfSO|pe&xip`>!&Q=eZVnRHX!Dhid4>S<*jTp;EO zO)awAX>hSptUduY;U~v}45jnup~v32nc`eqPpnUteRyLse4DJbpeVn<7wJ!gm#d&6 zLY&kRFHQ+&7~1DHvPAd%+3$oS9l?jL{SZuZ#d{uN*y@-#&yrkTrxIFx9;@b4_;PXU z`9X5obf&#(Dp87Ps!l-2Ns7dT7o0g9u$5K@X_sZ(Wf^x_#$A?imt|Zz%ea<8Z&o8l zZ8uiMA+$}mlKEQ6)r2aSGO55PPm)Eb%+xH&hkSuUj%{&N;zYGC_>u3NnG7a{X;j{& z?@VdpOq3wI*vmLvgEWN1-F(9F~mLJcj*5Dm@H^?ZBsjUG^K{1JV(g3 z(eZ!<&aR`uuwQa4&;skeG_IKzrZ;)grjgc01I~$o$-j|=y0S!jkixqV?)d2WC*nZM zLe|>{hE9ov?!_feaE`+_p&i}>&e-?v%eoPCO_1mHfHMI>5M*hncpU3?qQz755WoG2 zW6aUpYVBRc9BVR}v_EnS?FxIwueMv!(gV3NbxTH|;PYwNdPba#S32W`*tav^;JU<{fylOW>|G`6;~xr{1vhG5}s z7`FG{iwG|b!WZ4NMfL&C#X8A>Y~=+hM11Gb;=PlKX{oRuH4dhW!R+vGzK0g0{@&O+ zKzs8MGWTY1Iy_j6=WqfK4N?7C$xngXbUf@CAK|@^g#3LB$z?pa2NM1|3^)1U(v718 z`o^~D-4)G$_28(v`vj4PoR?K&Hv$x5PV0={JbefgN3P0u;Y6vN)X}u5-o{2;rN?0I zt9;`hpJd_-Vymv>Pmq*UrQ^so|11uKgnZFtt*FlItY^FlZm<=<-d`qv`!~^A;>SmL zFaG<<6A!8qZ3I{=-Y8xSx3qNvZ=DasSoBKZ1~Z^VKb~I8t~_RaWk2laB}DsbZ^KsN z@T}%hP#Q{^G5hNC7r0@o{d455u_xUY1;;{Z@Wr`dNx;?4g%kt%G0fl0ys2`!GA(ox z)b3o&(3aBEc9q?Rc}dEWzTP5_aofUd!fhcC-NPe}1vf2(ksY~1{G*{!to=D;t1ICU zeD(QDj-g)4t|5NKw>_(%*Wuatbi~h)a*7$GaSX~BghdRvg%9pl$c?JxVjGDB5|K{g zAXCH|2+wIyG%UF5-s%DBTF8~YS;s{S%;`jg0dsw)L zcL7ZVpo@F}F0%Ho$#0aQBXG6C9#|u`qE=X}cY$q&Tp#l}^knt2$cB9#+LrBA)6Ju? z?VVq2#k-c|hOHq#8jmKkgVEt=dbpLNq$~$(Y8AgOV7m$>Z!4R*hrITd_s84w)~zCvTwXr3s5Mzfldp1iJIlT1(1YvP(;_^Fa7=gF!)wP-_pM;2W+9Od~EnSVIn(m1ac zNg$h=9wbQ!+Cp3R#8iT9O#*8j9Q}YIcPHFiKO9p|@`{MW$+dCtLJUmP_=Om#R#~!( zVtCPXKFv#T@oB)NP79ld5K8+y2Mx{$dvA*|;=?KTmHvP_tJ@~LoNYoUCeJ3rgS?C; zDG}adVl@|&5tQ->FW z2UW>~sl>4ry2l>dzb4n@bRmwZ?%pG2t~kGWi1kw781?UXjNQcHA8{>^tl}>&Y=pKa z3VKVV#QD@7@K3nJ_bYgtIzO|iypiLTMae%H@L5WN6^5b!JVyc}WXW4SD!>(=6Uqdx z;zSHt(P>!Ou~@Q~G;$$sS-?to;B+BVE*u+O6Cf}Z=Y^g))(e-a2N2(hij%~k3zHHL z%OgZgEPRWt4If|6&(YWrOo^ywXWMeocn9IdoB*08U9YJK*B8LUzQZ13i`IIKeWy0d zlGk=!ZI9#0c2fEldPwIKwdBn&S!AGKAJw4fd+r@j<@cvW+ob-$}Cee?y)QIM7XH2|UfdhZRo@;u3xN_&i zS#ge~(jclJGx_&AUfZMqt>jJM&Gdw4Gyj1ta4UD|JedjmqV2`epg5JWaZF2IG>eMyrC8Qs_x!jPHNX2|Gj+J! z$Ny>AJdAoNVeSgiF}f^mytW{NuN}x%MhUy7wCGD?iBWO7;Tbh=8gj%lQd{W%jusFzQagx->j z%%J=vVeLOx_dE?ovl)c_@!oJcoa~Lq^TFO6TI0RB)jya|X7l0D9B(H^u*)!cGESWo zXP8_dPS(F5XtPFnCUH0wvQ2^q@`OrKV7`Qd5oZ1?j~1*<>^=&PDReu+`MR2YFG-NT5J%fVakkl&`_RP2Jhd~lr)uJge~O3?QyJcpxUS4Hk&PUhO5)V)FOF(rgEKplyjfKWSqJprZZMm~*F zzG0Z`mLc2rM6wp476Od&vB)=CHpv9n7u0@dQrx=4StJ z4=(zX#lRd+(ZotdaTh?mg5C|676{s}Z~Lz~Pl-#7UvvB8VnhCfm>EZX|FUW0$QbsA z{k_3pZ!o;-&yI$}qyE9ajh^uf^_V~HE9x<0EAcr|CkmHZ4^sJ2BD==@oJ;^I8!s7T zP4t`iUPr;Dg|hgtT)~NE+8R#TNevAbjOqzgoD$^{6_@u-dn)dmA%gl7@>?p2o^iS) z)I}G_qZ`+Z$%WXHZ^lQoK3_d}*o3xmG&~p|9vsa2)7g03$)G>hLU2!w;WUF`ER9}? z;W&libUYr8C;i!YoWd|c@NHr^JvK?4!N}KKb#!SW~1?B zHcT#P?D5kfS5xwDgX$Ye{w-0x?iS!#s6MR(c8coLDqx4GKBfTtbCW^43Lx|7xfOse zLQk&%bTO-_0Cozw7L5PxA=jP)XiW8OD}Xkreme@FrL}8e7qC6#TG#_@3%RTU715iS2ka69ypZ#NXJY`}^ML1KfS6jaAcH2hR9a!D zc3EjXu~W#U6~;~>_g%S+b_%()me?ue(t2a3kV`9&okH%r@+R#NaxtwTE;Lc;j6r{V zI60W6Ha`Bd7I!^r%OI^Jo)??!HsU$4$vTdn6Pv83=sB@T3;O59CN0^Y7n|%};5o6$ zI)a`Po2=*O`LKye=O|60Wq1D%ao&5_pN#s`U~5;?d#A5(BZ?`L*wg-CIGc=zgK=^j zp4jWPkDI0dANGfnS^sc6JWNg8=wLiLoJ~gKgSJn;3ef9Ldn-A3c82ED@_nahJ|pgT ziRP8^zlpbBfo6{T=@}J(Hbz_a_cuYU>WOdU*33b#WnW@N7fzl#Hu3xk@oP^NG$;SI zbwMlS--5S)i{ziN_;-x_(@J5t$UmVK=q+-QV`CF;91AkkMFX{{9J*+rE*fYzltLE` z^qk0jAJISxWzaxgaM2PGPZY|zK@Z(Q!ZYm@e#9uC z9ZI3;juN`Wu_p@k*&(V=sDaofq0<7L7U;A2Qj>yKgd&WBg=XO*U*spE+5&Jm!KjFRj`N7%9N~ZmuaV-88e{z7w zbVHaA^|7Q3cZKTAK`%PxnZu!kMU#WOE*@j3f6IOtl!|SwDtNlUtO}vT>nbxM%Eju; z#|OVc0vZ~w2zCwLi%c<+P`XizC71w^!6^Y c+|`=#gG1x-@yp}?3jhHB|LYCx+8_)A0LC`n1ONa4 literal 15813 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 cbg.MaxLength { + return xerrors.Errorf("Value in field \"RemoteSealingDoneEndpoint\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("RemoteSealingDoneEndpoint"))); err != nil { + return err + } + if _, err := io.WriteString(w, string("RemoteSealingDoneEndpoint")); err != nil { + return err + } + + if len(t.RemoteSealingDoneEndpoint) > cbg.MaxLength { + return xerrors.Errorf("Value in field t.RemoteSealingDoneEndpoint was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.RemoteSealingDoneEndpoint))); err != nil { + return err + } + if _, err := io.WriteString(w, string(t.RemoteSealingDoneEndpoint)); err != nil { + return err + } + // t.RemoteDataFinalized (bool) (bool) if len("RemoteDataFinalized") > cbg.MaxLength { return xerrors.Errorf("Value in field \"RemoteDataFinalized\" was too long") @@ -1547,6 +1570,17 @@ func (t *SectorInfo) UnmarshalCBOR(r io.Reader) (err error) { t.RemoteCommit2Endpoint = string(sval) } + // t.RemoteSealingDoneEndpoint (string) (string) + case "RemoteSealingDoneEndpoint": + + { + sval, err := cbg.ReadString(cr) + if err != nil { + return err + } + + t.RemoteSealingDoneEndpoint = string(sval) + } // t.RemoteDataFinalized (bool) (bool) case "RemoteDataFinalized": diff --git a/storage/pipeline/fsm.go b/storage/pipeline/fsm.go index fc0a93a85..264a6ca49 100644 --- a/storage/pipeline/fsm.go +++ b/storage/pipeline/fsm.go @@ -7,6 +7,7 @@ import ( "context" "encoding/json" "fmt" + "net/http" "reflect" "time" @@ -14,6 +15,8 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-statemachine" + + "github.com/filecoin-project/lotus/api" ) func (m *Sealing) Plan(events []statemachine.Event, user interface{}) (interface{}, uint64, error) { @@ -142,8 +145,8 @@ var fsmPlanners = map[SectorState]func(events []statemachine.Event, state *Secto ), FinalizeSector: planOne( - on(SectorFinalized{}, Proving), - on(SectorFinalizedAvailable{}, Available), + onWithCB(SectorFinalized{}, Proving, maybeNotifyRemoteDone(true, "Proving")), + onWithCB(SectorFinalizedAvailable{}, Available, maybeNotifyRemoteDone(true, "Available")), on(SectorFinalizeFailed{}, FinalizeFailed), ), @@ -218,7 +221,7 @@ var fsmPlanners = map[SectorState]func(events []statemachine.Event, state *Secto on(SectorRetryWaitSeed{}, WaitSeed), on(SectorSealPreCommit1Failed{}, SealPreCommit1Failed), on(SectorPreCommitLanded{}, WaitSeed), - on(SectorDealsExpired{}, DealsExpired), + onWithCB(SectorDealsExpired{}, DealsExpired, maybeNotifyRemoteDone(false, "DealsExpired")), on(SectorInvalidDealIDs{}, RecoverDealIDs), ), ComputeProofFailed: planOne( @@ -241,9 +244,9 @@ var fsmPlanners = map[SectorState]func(events []statemachine.Event, state *Secto on(SectorRetryPreCommit{}, PreCommitting), on(SectorRetryCommitWait{}, CommitWait), on(SectorRetrySubmitCommit{}, SubmitCommit), - on(SectorDealsExpired{}, DealsExpired), + onWithCB(SectorDealsExpired{}, DealsExpired, maybeNotifyRemoteDone(false, "DealsExpired")), on(SectorInvalidDealIDs{}, RecoverDealIDs), - on(SectorTicketExpired{}, Removing), + onWithCB(SectorTicketExpired{}, Removing, maybeNotifyRemoteDone(false, "Removing")), ), FinalizeFailed: planOne( on(SectorRetryFinalize{}, FinalizeSector), @@ -736,6 +739,16 @@ func on(mut mutator, next SectorState) func() (mutator, func(*SectorInfo) (bool, } } +func onWithCB(mut mutator, next SectorState, cb func(info *SectorInfo)) func() (mutator, func(*SectorInfo) (bool, error)) { + return func() (mutator, func(*SectorInfo) (bool, error)) { + return mut, func(state *SectorInfo) (bool, error) { + cb(state) + state.State = next + return false, nil + } + } +} + // like `on`, but doesn't change state func apply(mut mutator) func() (mutator, func(*SectorInfo) (bool, error)) { return func() (mutator, func(*SectorInfo) (bool, error)) { @@ -812,3 +825,41 @@ func planOneOrIgnore(ts ...func() (mut mutator, next func(*SectorInfo) (more boo return cnt, nil } } + +func maybeNotifyRemoteDone(success bool, state string) func(*SectorInfo) { + return func(sector *SectorInfo) { + if sector.RemoteSealingDoneEndpoint == "" { + return + } + + reqData := api.RemoteSealingDoneParams{ + Successful: success, + State: state, + CommitMessage: sector.CommitMessage, + } + reqBody, err := json.Marshal(&reqData) + if err != nil { + log.Errorf("marshaling remote done notification request params: %s", err) + return + } + + req, err := http.NewRequest("POST", sector.RemoteSealingDoneEndpoint, bytes.NewReader(reqBody)) + if err != nil { + log.Errorf("creating new remote done notification request: %s", err) + return + } + req.Header.Set("Content-Type", "application/json") + resp, err := http.DefaultClient.Do(req) + if err != nil { + log.Errorf("sending remote done notification: %s", err) + return + } + + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + log.Errorf("remote done notification received non-200 http response %s", resp.Status) + return + } + } +} diff --git a/storage/pipeline/fsm_events.go b/storage/pipeline/fsm_events.go index 1fbd94fd0..f92f527ad 100644 --- a/storage/pipeline/fsm_events.go +++ b/storage/pipeline/fsm_events.go @@ -524,6 +524,9 @@ func (evt SectorTerminateFailed) apply(*SectorInfo) {} type SectorRemove struct{} func (evt SectorRemove) applyGlobal(state *SectorInfo) bool { + // because this event is global we need to send the notification here instead through an fsm callback + maybeNotifyRemoteDone(false, "Removing")(state) + state.State = Removing return true } diff --git a/storage/pipeline/receive.go b/storage/pipeline/receive.go index f06848bcb..e5eec5ab9 100644 --- a/storage/pipeline/receive.go +++ b/storage/pipeline/receive.go @@ -211,6 +211,15 @@ func (m *Sealing) checkSectorMeta(ctx context.Context, meta api.RemoteSectorMeta info.Pieces = meta.Pieces info.SectorType = meta.Type + if meta.RemoteSealingDoneEndpoint != "" { + // validate the url + if _, err := url.Parse(meta.RemoteSealingDoneEndpoint); err != nil { + return SectorInfo{}, xerrors.Errorf("parsing remote sealing-done endpoint url: %w", err) + } + + info.RemoteSealingDoneEndpoint = meta.RemoteSealingDoneEndpoint + } + if err := checkPieces(ctx, m.maddr, meta.Sector.Number, meta.Pieces, m.Api, false); err != nil { return SectorInfo{}, xerrors.Errorf("checking pieces: %w", err) } diff --git a/storage/pipeline/types.go b/storage/pipeline/types.go index 81a2a2fec..cb1d84383 100644 --- a/storage/pipeline/types.go +++ b/storage/pipeline/types.go @@ -94,12 +94,13 @@ type SectorInfo struct { TerminatedAt abi.ChainEpoch // Remote import - RemoteDataUnsealed *storiface.SectorData - RemoteDataSealed *storiface.SectorData - RemoteDataCache *storiface.SectorData - RemoteCommit1Endpoint string - RemoteCommit2Endpoint string - RemoteDataFinalized bool + RemoteDataUnsealed *storiface.SectorData + RemoteDataSealed *storiface.SectorData + RemoteDataCache *storiface.SectorData + RemoteCommit1Endpoint string + RemoteCommit2Endpoint string + RemoteSealingDoneEndpoint string + RemoteDataFinalized bool // Debug LastErr string