From 4d8d055629aa303b2e267a94682c4450d9114afd Mon Sep 17 00:00:00 2001 From: harkamal Date: Tue, 12 Apr 2022 13:20:42 +0530 Subject: [PATCH 01/11] Snappy frame encode big payloads as chunks as per standard --- .../encodingStrategies/sszSnappy/encode.ts | 13 +++++- .../sszSnappy/decode.test.ts | 27 +++++++++++++ .../sszSnappy/encode.test.ts | 37 ++++++++++++++++++ .../serialized.ssz | Bin 0 -> 139405 bytes .../streamed.snappy | Bin 0 -> 52357 bytes .../encodingStrategies/sszSnappy/testData.ts | 28 +++++++++++++ 6 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 packages/lodestar/test/unit-mainnet/network/reqresp/encodingStrategies/sszSnappy/decode.test.ts create mode 100644 packages/lodestar/test/unit-mainnet/network/reqresp/encodingStrategies/sszSnappy/encode.test.ts create mode 100644 packages/lodestar/test/unit-mainnet/network/reqresp/encodingStrategies/sszSnappy/goerliShadowForkBlock.13249/serialized.ssz create mode 100644 packages/lodestar/test/unit-mainnet/network/reqresp/encodingStrategies/sszSnappy/goerliShadowForkBlock.13249/streamed.snappy create mode 100644 packages/lodestar/test/unit-mainnet/network/reqresp/encodingStrategies/sszSnappy/testData.ts diff --git a/packages/lodestar/src/network/reqresp/encodingStrategies/sszSnappy/encode.ts b/packages/lodestar/src/network/reqresp/encodingStrategies/sszSnappy/encode.ts index 1bd27bf40325..5e0266654148 100644 --- a/packages/lodestar/src/network/reqresp/encodingStrategies/sszSnappy/encode.ts +++ b/packages/lodestar/src/network/reqresp/encodingStrategies/sszSnappy/encode.ts @@ -4,6 +4,13 @@ import {createCompressStream} from "@chainsafe/snappy-stream"; import {RequestOrOutgoingResponseBody, OutgoingSerializer} from "../../types"; import {SszSnappyError, SszSnappyErrorCode} from "./errors"; +/** + * As per the snappy framing format for streams, the size of any uncompressed chunk can be + * no longer than 65536 bytes. + * + * From: https://github.com/google/snappy/blob/main/framing_format.txt#L90:L92 + */ +const UNCOMPRESSED_CHUNK_SIZE = 65536; /** * ssz_snappy encoding strategy writer. * Yields byte chunks for encoded header and payload as defined in the spec: @@ -30,7 +37,11 @@ export async function* writeSszSnappyPayload { const stream = createCompressStream(); - stream.write(bytes); + for (let startFrom = 0; startFrom < bytes.length; startFrom += UNCOMPRESSED_CHUNK_SIZE) { + const endAt = startFrom + Math.min(bytes.length - startFrom, UNCOMPRESSED_CHUNK_SIZE); + const bytesChunk = bytes.slice(startFrom, endAt); + stream.write(bytesChunk); + } stream.end(); return source(stream); } diff --git a/packages/lodestar/test/unit-mainnet/network/reqresp/encodingStrategies/sszSnappy/decode.test.ts b/packages/lodestar/test/unit-mainnet/network/reqresp/encodingStrategies/sszSnappy/decode.test.ts new file mode 100644 index 000000000000..d7299d6c297d --- /dev/null +++ b/packages/lodestar/test/unit-mainnet/network/reqresp/encodingStrategies/sszSnappy/decode.test.ts @@ -0,0 +1,27 @@ +import chai, {expect} from "chai"; +import chaiAsPromised from "chai-as-promised"; +import varint from "varint"; +import {BufferedSource} from "../../../../../../src/network/reqresp/utils"; +import {readSszSnappyPayload} from "../../../../../../src/network/reqresp/encodingStrategies/sszSnappy"; +import {isEqualSszType} from "../../../../../utils/ssz"; +import {arrToSource} from "../../../../../../test/unit/network/reqresp/utils"; +import {goerliShadowForkBlock13249} from "./testData"; + +chai.use(chaiAsPromised); + +describe("network / reqresp / sszSnappy / decode", () => { + describe("Test data vectors (generated in a previous version)", () => { + const testCases = [goerliShadowForkBlock13249]; + + for (const {id, type, bytes, streamedBody, body} of testCases) { + const deserializedBody = body ?? type.deserialize(Buffer.from(bytes)); + const streamedBytes = Buffer.concat([Buffer.from(varint.encode(bytes.length)), streamedBody]); + + it(id, async () => { + const bufferedSource = new BufferedSource(arrToSource([streamedBytes])); + const bodyResult = await readSszSnappyPayload(bufferedSource, type); + expect(isEqualSszType(type, bodyResult, deserializedBody)).to.equal(true, "Wrong decoded body"); + }); + } + }); +}); diff --git a/packages/lodestar/test/unit-mainnet/network/reqresp/encodingStrategies/sszSnappy/encode.test.ts b/packages/lodestar/test/unit-mainnet/network/reqresp/encodingStrategies/sszSnappy/encode.test.ts new file mode 100644 index 000000000000..2a206e6cb08c --- /dev/null +++ b/packages/lodestar/test/unit-mainnet/network/reqresp/encodingStrategies/sszSnappy/encode.test.ts @@ -0,0 +1,37 @@ +import all from "it-all"; +import pipe from "it-pipe"; +import {expect} from "chai"; +import varint from "varint"; + +import {allForks, ssz} from "@chainsafe/lodestar-types"; + +import {reqRespBlockResponseSerializer} from "../../../../../../src/network/reqresp/types"; +import {writeSszSnappyPayload} from "../../../../../../src/network/reqresp/encodingStrategies/sszSnappy"; +import {goerliShadowForkBlock13249} from "./testData"; +import {RequestOrOutgoingResponseBody} from "../../../../../../src/network/reqresp/types"; + +describe("network / reqresp / sszSnappy / encode", () => { + describe("Test data vectors (generated in a previous version)", () => { + const testCases = [goerliShadowForkBlock13249]; + + for (const testCase of testCases) { + const {id, type, bytes, streamedBody, body} = testCase; + const deserializedBody = body ?? type.deserialize(Buffer.from(bytes)); + const reqrespBody = + body ?? + (type === ssz.bellatrix.SignedBeaconBlock + ? {slot: (deserializedBody as allForks.SignedBeaconBlock).message.slot, bytes} + : deserializedBody); + + it(id, async () => { + const encodedChunks = await pipe( + writeSszSnappyPayload(reqrespBody as RequestOrOutgoingResponseBody, reqRespBlockResponseSerializer), + all + ); + const encodedStream = Buffer.concat(encodedChunks); + const expectedStreamed = Buffer.concat([Buffer.from(varint.encode(bytes.length)), streamedBody]); + expect(encodedStream).to.be.deep.equal(expectedStreamed); + }); + } + }); +}); diff --git a/packages/lodestar/test/unit-mainnet/network/reqresp/encodingStrategies/sszSnappy/goerliShadowForkBlock.13249/serialized.ssz b/packages/lodestar/test/unit-mainnet/network/reqresp/encodingStrategies/sszSnappy/goerliShadowForkBlock.13249/serialized.ssz new file mode 100644 index 0000000000000000000000000000000000000000..1be96160512e0c5d6759b81023c2c5705bb78fbb GIT binary patch literal 139405 zcmeFa1yogC^9OwCZlokGrGRvIiAYK+jg$x|DcwkigoJ=dBPA)_-Jk+WiF9{2eAg#^ z-j~Z&@&CPRecyA|f_v_nGka$L&dlDkXU_ox002-D7e@Ok$2DMs6vx=BNmT9%dm{^v zQsyH5EBzrTC-yY0#kqnKc}{x@k{F*e86rfq4<9Kk@)I7;?Co8_(I`U~=nPbLMSnG@ z-ex!|lL~9mj+7znkg&r9K;I5*X82vl~tLYHxDQ@M9i7$Nd#!j;^BYFb$BSd5Kh3C zp?I@!r&_l_q=Iq3;XcKV%voc(o9mKEo5*43t3cUj^+S?s)l_f4qz~lp<#~P8ksH(l z29WL)&;S5F3;=)%3jjdD0RX$8pCxzzU>pGe_=pGqbRYo$wa5TK5efj1i3$KrgZS$H zum{jBza5b5;T1^E*JFw};-#t*AA%+6`w#V6+S!eD6SfsM_$$iqno6G)YZ1l&aUZ1i zN+mkD(AXELqv@VA=6n?0;iD{Ta^HZmJW~ztPbAvz258?lEk7zv#7~4tM^NF4gH2kB z@-Aq@9pw*cC?Nt|UAJY?=$zINHnwJTY0aIRw>>kKS=}-1o`J7a$xVBxadxz{lW=x2 zw>D~aT6=VS0{?BNLHPW3KvMEociR65K{wc_C?(-`p{G5pjiOHgJl1vC_beq(gg@S} zun|>8s3M$`rKetvA`$U6e{Fyf|8O-@_V@uzaTFb^0$Mv8Mhuk0ts?I3u{YHOjx2hW zgI0KB0se<45B826)3*yZM$bl0=Dr+{o|U?t9IgpreB0?i`V9DgyVJoDm`To0=ZSrt z)emUtk7NsF8$MK`zQ`6;kg}ZtqA=zPZU()^c8)UFi0Iifb-jyVj74R`T`)K^G`WM6 zU14?2x%W}44>Jn(^Ua)>03wcFxmxDJykwgbx1;-H`$fz9r)O(!i(^}7vukG~<)udm z-*y`01^<&Lo$e57Gebsp@0eK6WVSl-L7<_#!m038*#(iUFW#T8r1CU8#_rIfpFfek z4u?8(&x4@I!8W|MAg%G8F4H9Ru~o&IOh#l$Bs*lSH)Jt*Rd0JmP9mwMtXlMrB+E4u znZ<9XX}Z}*iz-$KL#?;O!mL&^v?YbAu~Ud3hO%wn>LBnZzqSL0nYkY zwc}`E+z?~p7+IbqT9mvN;3o9x5~7?_#f{v+6A;9a6ZCY~XDBzg4l|NkZhd9LK||$T z0_k8&P0U=DIMRrS_v5CeS;kv~&9(QP&NTA&7DAM|ZcMN!5wnyi-sI5BBSTl*Zb<%m3bJja{c7N)= zhQmoZ?6;i;#WequPUq%RrrS<9Se;D=(>svG6zicZRhThz8gp9{CvsZmYAgF2>IUiZ zLElQ&Q3+DgsllPX2P*>4i^_P z7vLJ99zSTll7dte+PyX!3izTOED!~7Duf&Pj$Q@5%R|;%-PD>_D zPdmy_-3m@mC;s8n|EnjRHP{}2;1e7|7f-0-@&04P!f4Fa2$BjVtH?dCJYuM@YoAE+ z(+Go>7rs2SVUBw?0;t8f*_3pzF7zqcv&I$Q!D!jZ5#i$XL2Ep0uLb{*)fwV^&6j%I zEH0RVeTe?e+yF6HOiYmPqPPP9z+NB~;b0)OZLE(02K~hJ>QC)sJ8)UNqtpzgI&H|pK?1pTE>~x zV5B2_Kg`w4pCAaIZZ5E>s`F`;w6ND)rCw)SOsy1FLPCOl z@S8#FSiqlFh56SR=qY@4uHOilf0Dmm`Q!Ne(x36f?*z=>c|@TBUxO>q59mf=0O08# z-@e}TN7RK0{QBi@fv~@Q{o@y?nXkw1*Py?)0Qg%DG~mw=9SHFIdK>8Ozcm;BgX=2+ z01E{D`pWq`w>#(zbO?iffWm)>{<7}57Skz6Mh)Ta+lVfHZEJ$33>LXf zV@USFR~`TW+wr##IVj%WKK&ZR^}e1QgL+8&QYQGfi(r0vEMo{Zk8y~Ltw%3R%+?17 zP|u7M>mf@JOd>#KV5#bVZG!;BD+jW4VNj=OL95LJN&o;!2&DM|3>(~2BvmgpBPM`X zQy~)&c|-hJQF|9KAOHvKTo z|DV@>@i*u;;Ds$hal3y@M>~8;SH$Os%UrTUPN5srQnr=c{w@8S^S^EL93sf#gwMVF z*F|UubU;(NyJ^f{w|~b8n_4q;!--eVC*gI>MBYMkYW2ZqVA&{rHqGn7QvW0*{(160 z_!NE9C0Zb;FE%4f={?8$R5!F??5bLwt0(~+8Nsu~u~Sc^yb=uM)x}Vtf*M=ewKAW@ z%BAV(5S#$`iKd{aNQKA5zk4HC)$807i8g}+=SwWOES8`(6Z6a>D1{Q&P1bl=+fGBA zSRzmO6Uj&x(hezB{353u-Cq|;X~eUw#NS86P&>^nYCNOZTTD`PA)gypfWQtfCu=nS(VKS$`=e>wX4}c!yLesf7=L`6qQgR@a+o+PSVe zriyNLP>E%Eu{PqJcbpErn626;XXkKd^iSa<#l4=!0FV?U?M)J~xd3$~G?M%p9O^;^ zVbCS5miN2VsIVjWtxO?6J~&po|u_jgYPA0)%}e6&z-G7jaN?o!&RkLLCV^|Z^4 zV;wtZBQiuttsEt$@}RG@{J8@bbkmN`l0jEIz7D#&j)v$>YWa)S->8R@XDCxY= z@m12H)$vo(q15sJdS8H&PPtB?5@RB&P@*;tPB_!Mz#UrqLEqbZ)shCZZa8m!NCHZ2JeFrO2FFK?*!qC={UfP=>Skh^@0OG47{6P z!1fIZlzF}QXzmq<^4X*0f9~p1__-CPZU#`I)baE>pVQ$Wtd@7G1tj`Kt?P;B3yO<1 z4-d9}ur82J2`Wo}+hu+{{OM>@+s3fusi`^Z#?(dpUuk-u%h|aWh)73CbWx^Ukq7b! zuh>DaBblz|`tbz%P_kUej~{m7tP0|VFw_HZFKiz~goKZ(Qpdf=vUS(|In^*+cQ}Mx z>u#(FSU4KdAGHPP1#W%5sC^KA!aXF8gi#q?&Ayc8I@NmGk(|C2R%f!LO`(zS8>5tW zS1;oKN*lI*dd8XEmGH8V zTq$+h`bs5ctq$}+Y&lj=Y7JV>`d!Uq!lqV_@fiK#PJlbvm(3b>VaH!!ouke4S*(VuwM z3>JpC2|BO#3|_?ll?JQTI+MfPj;o_4)!weVx~!$5rjMs`OzDzY3x6t;6nh~*epuLr zbjZZ7LGgtLBzz#zFKQfw-|fDZx6u8?UD^X>S-tgET7>~vE=p|^1JB++A#!Q!y~cSF z|5uu9=vay6!%Qx%LU-EN4?a=x5j?8!-M^M=Dbe9e8eq_OAwPcD^9$*aiCBr0f?^()H#~^B?*OCHg$>IA~tP|CP4E7?XG(nPkRx z{biJD0=dfw`X@41+5O`uhHX=byV=AS^5chvUr2{c#DR26HYhx6G!#s4dct!z&O5S= zTI$O>n*lf8>xze&qonY_OX4Rz$YNB!h}V;DGFKZ`IBh6fh8eO@l@(OVSZYKa>o(N` zNk7w}v<=Nq7!usAZ zuTj~vsSJ)KQqb&(=l|Rn0IOyU8?*D??$8rLtO!|E_7=QOHIMZClvl^kleUOIK(l7WS$$u&v+4_(FdCu&4{^kclLaZW&&uh$YLc zhPj*Dd;7)KRN(}9{tVsP#PqX+mi~P*Z=Xxzr>N2}MXPJJ@vwcIPu@z0NB$!=4l>Qipu09VBAm8k2}OpTYRlcZP)N1ZoI?#CUMWTKk{T?TEP!{ z0fzFumoFY4K&?Q+2NL}vML_`GrD>R;*pB+UjTLZbMn);=Z|Y5&u`355JY$hRM?B zvSGI_1}U8eo6~j!32A*X_@#Atnh$6fudngLeke_LjxPA;T>Hl*Nccda|D&=0_yWRD z4fEhijeigO(9!E8&Xp=_i(RZxw{RBxcvU9(9k}7}5C6gPUtc+vn#jkU zx}&$0tbyG1w9_+kpti^W#_{6y8GhKs@%4X6`>zXE|Le+sTxd@>)vdgO4}^jd^~_Y5 zb!AFYRAog-%=}2&C2Mb(9C%6mG&EPU{pZJoQA$(Xxvf7_P&q1;vDTjCq}H}Ki7Zwj zl>LV~|Mj(M?)3}H((sRgiJ0Q9V&tX^aPvY^XmRv%(QOP)B5}+A#qjL~{IHkbe*KB_ zi{ndBgOKonM88NUko{>TJg75ipOcD;6oz>pkkeJ8zuzzyxQLkkIy<13Y$50VMf_iB z^;4?77{TQlIL8fPgvmRtvW|>%9tb>VVvn7X9w!DuSYJWAU)(-)-NkeS;Kg(#aCC$h z_LVs^v_9aTFIsp!3wMMuBDnPfe6$}`fATH9IPmf#1e;vtGQiNGNyp*MSXHocz|fK8 z)3(c@<0DSN(BYqCSyHtNUgePtj(~J~%qYz`I>m@Gn{r)qohR>0?PuBWZNnGF z|DZ-FNU6s|-de|vpcl+$O;Wp4G2D`xUWIlPorR)7nVk&gqM&?~p;U$7KR2Upk~v}F zwvx$F(-5yvTNfMi%(Y11?G@(^4yTZ&Q0g@zhf0l&yHz~8Z*VrREk8R%v7Wdx=)+Ls zAQEJ|B!Km~{-aOcWMAfh@2t1Ig>3NM{=AqZIR&I-f9hNgQn7SH>RPW*BMRx{`9_fj z*!+*YZ{yzi;+0^v!l2%~Gql<6yAdy%e+#Woq=z;m`W+s(4|zZDz2#kr;mO{=jS zj-Sr7S_#Kf@g;V#_U)Gm4RhLrg8G3>VORS*Y4WrRNR{bO z(4E7DM^5gjW#jc^J-?nduGv||Ws~Dyn3s6?tSH8erlv4FM&V<9_rjGc1%?44)+Sqp zGfgsh{wlXO`^EhN?J+eB!zidGUBVGp?kLIi4VlRd$_>K-?q3BXYb12Biw2Iss(~hIkhZ2G0=(74ESrbpF9+!t9lM+0Mj= z&vTxX=xi=1P@&G3Y&YfCR>gft+kJv&XVB3AJ@ACXR#<7IKyj6q2#)+Js?dW$ecs{i z^@Yaj~Z1JZkCdl$%LmC zjW%7i^TSxyU#klDs8eWU7%v{LbU?d;N9=>gnGXlMIh%-H(M{EQ(m^QFs)@mq1V5?# zG~CdOiNT0(U?nCBWl;|IXh_)BSU64aU?`tWAnN1Xc8C}ojPB6rAxwXv9T_*GM{_*~ zK7*z^a-*j5=EF^S=a%MI2IV`wghY|s3ZIiv1wWUzlV&B_8WWSxHX84Uv#XVrnoHG5 zUUPZm6P?&Z9a$6?X5~4gXV(L3WWHY7()CAb*cF1Yvswm$N!%ZU`!N2f9{+%MzMtu1k0K+9J1W!CxY>Bt4+$Ri z99%^M?PpU%+Rr9Rt!K!Yg@82>0v$p=2WtFcei)sL>9FG$)8XqbrXvbpOhG=Tw5c9eJpRR|1jK3swpJvbEho_%cF>r$`+QnRwoBAc2F2t1$p4gPgf|(D; z> z5LV*|uO}4rkWYGheNRWo*PS4h)Z~X70${d{d*tn%pu!?K_d6iXJT-JWROrut_2VNh z`dXb}^bxs!*wgOG05bkn&?Yuw$Ag)Rq4`Svw_fRT^-7nIAOEd)g0SCku@PT-e*3px z3c`NQ|1tjm)>}c?FS{iElF<6Kg;>6p)oAIj!wny%S6ZmU*Mlo^0r-|=8EzC>0DfKk z{%<|lrS>}^k8g~LoQH~l4$^pZiQ+C@$!!G(ErX*cMdA|&J-F0I4izD6i3Yq)&@NJ* z^W%4}c7@Znk;-|+W4aMFo57kQDaYOQ@;`)nmkZhuy9QxHtODwtm}D%5^@SGsZw25b zD*z!rakLBZ2S6oWOeY6kOc%SD4A8E-_y%Y9i|KDKCIdz^D*J$KM6e5_%hR@!mT+p7VpX+I%; z9r;B^6UI)yCc{}jTbKD>wPh5`xH46J$Ol9v9HFysjy)5RMI^xaE!oEped@QT4vt~A z4x@j0IC30F6*`pG9)o26$V*#p0uc_Wv*6C+`Mf`>1v8={7%igfT1_@N4CRyFi}%~j z6kD`b+`VSluZ@G9K-YmEtW6DzHIV|qefsu32mV>=bDi5Gk)xGIEGGimy};14E&nf$ z8P^u~w8>OX>X8_r7DaHM1!}<1#q(yzEjGeHt$xNmFQ5U|nw@q%!+B!WUr5p%rayG6 zQgjkag8rlr#bZasB8?07FAz_3b|ULEhCjb`2b|y1u@!a(A?tx|r;XpdHse+D+&43) z`=j!7SOt~bk5rEM1l#K#pgy#FQ zX*Jo4kQ@Gp!G(vzah5r`_ep&G(*4uevtC|KO{lDj~;xzY&scr#%p8j=se+zD7! z`d+HXAJ=!Hk%(8?pZ7V#U=RY%=hSr$e7-=FI8*eH_Vq~#yGj1$J0bPrTNJ5Ok_A?0 zpXT9^oF>1lpU?aAQX8ifX5XmPKR2MBxk5^!iW*h)Nv=DZ$3pHJd&k6mj5=7Tw&Xfo zBkAHaj_wr?{bi_Bk2oc(l&}sWAl{f%1E897WuY#X!qtQ${`j*bTIl@QMArT6$&p6e zZ5XIE&hyRW89PS&=pL#`+=i%P2ZIZjvfE<6!?BBVA$27`02x~08-vs5Dp#V|)U5+! zFyCWv6Q7YtRKf87fF@d<8{0b}3g9$(r&yc&mOU0T|Jn+<4h#hw`zQ;1Ut_DpNNa_j zJfQgHHwH&0P2odsX_~`DUKONQ=&*l=$pQ^@vkSR5uY}YgjPwTAw!6zbPZTfDj%0t18m!h7L;Dd%Yz^#NC$Qb7Zo zSnB`^G&JeM8X<(UBTx&KIb!m)PW_##UxJ%H&(v!cxgjP3d2pp#-!F!=@#K%c*EA#) zp(snh%R^8YM3A}PQ+r2e8j2lPlY-PvPdxN&chnj;e1Id#4zJ-6P_Lg7+SWOU!ZYPK z$58)uZ$v$w2>m$o3R$-QhhYNJLL{;qT3w|mtN_6I{M6QB4@2VH=$&R@=|H4f^X3i8V0ZspfkNYde9UMhwX)Zu<;7HPSrn1~2ZAmK4)D%G^8 zh-C{@UO*!e$#cCTE`}IzLo4f8cs4sOEvGdKv9Cj^L-u$qM!#z+i=lj5yo3HO{+DuFx zO^;>D&MDq0M-zrcJ)ppM-b)k0Pt}!0!n}Ep@VQhj$al~6!SC@QuE#Px?qK*K$w!3J z7klc42u?hbv3Z81%WEozmliMQA8X*Pe`xHxF;BAgCYB=zS*_O#1q$BiiS5P-)hAF3 zKO4AqoZt1cuqq*Be)4QJK6I&W9JfL;V6MfHPs4EWmkh4=$w#w)O@aHIeQI6d2b#wK zFd%#nh}?QNop3_M)2dW=0M~}%M9ZG*$8&@e7{j1mcN_7HPF|r8zVXNszh{i=$oe%}#Aeol(ZaKaht$-LFW*<)@j#E3VdBkgEhpyp zN$zSpeYJ12Q!;;F25hut5yE>BGjeR>TqUqC?>CH&mj$LZ7)}RrJcz*BnW}pK>c&Ka z{oRjIgCZM*hf5e9Sz&nKM!ci$2bk176$u37ay9%kPr~iq3kb)>Q46Dpba_V5v}s*( z#M=V1bb=)IQX`%%`>-(X(}NrJ@Q;ukM8k=^Zq2Z;^Jn-p0&hye5<)Ry=Y^GzJUH5u zJ}TNBw%($@#r{bT1OHvC3_G}JOYQ3Hkd>iTYZN(^DT8+GgItA?_Bpz;S=;>O4z=kv z#$OR_O|`a=4T6cbAj!XUv_;vchbOuv1sW{8JvTzMfO`s~5?i)jX=goILJD7iV$(d6 zIye2DpIL-a3+pJKxhfhnI1eGfRG$=#-4h>p3k7$+YZM*VJ|Te;P1!P*vbj!y@RT9* zo>0iqP1R{~N2vpefnZq5HbR>7S--<03rXnC4~~n@c%y5(dYagupL)G1kdXaDbh}?qRD3FbSb;f>v(FgWXR(G zV?@&%eq`%@eoNnjpE#I!RPd##e?@e{qlyIj zs|x2&hmho7K02{4Hf}{-cLq6Y)%An|0ecN~xeZ2z$(uDutQtXrz=nw^{0gFx8}tIG zP3Wc9Yaav~Y2@BM=1qoaes!WbYY1*C7iyfYua z6p2aB)$;w>B~gk7Ghsp!dnuG+hF;eFbZqwJd^d1oSJvAgnR@hL1iC{JL+W16vp^fi z`2P5{t8g**az+2nF7C73SRaL>$=3wg^G`1qcxC4mg~9OufF@USd=?XZ>A`72i9o=v z{F1u{Hzi?o)Y^8XK5YE`OUBpYotUW!MhuL?-$c630f2?&u#tZidnLEHI}LbG3S9Vs2E#rbEeuay^Xy8ej-^!{ zfs4*tzo@4TgzmXd4&Ky`{)+Hpx;iz90L**{N&cn74_YC(6_?o<5bp1rb6#0+Ejbw? z?C5O~z0k`>mq-FWW=FQ*EYnARa$il3%9}lx#2co9wkcpwvW}CW#z!*(oUbC?eTE91 zV%!6V(P??dIhdh8@ikR70Di3Rj+R92n9;t3RNL^`|znzFK;4n(RfrbiAD@ytm@l9;toeDU*sWyl`e#?KBn9@`<;o?#4I1 ziaXns_+qH8-mlD4+hC`L!Y`(5A6RfNWafaaxOH7qLM2sNb4RHmND^lRcgM*WTU=-= znhvzDa{c_Q{FCP_Ztq6LF>A<6ENC(bM4#A0nM%mKr9v8Dg1V3DbM-GYf8V0ocW%Ef ze11#cu{SV<$b3HU4{K3A17?SUGA%C`=FGLjobN%A_VMf_btRDlB`0>}w$0)h*;ukN z42GyMZtVdE&CQON%CG%xp(R?q#+uZYt$?rN`(a213sfW4(dF?7&PZonrh3?_sYl+- zPFWghvW$cC+sbPre0zIw&gu!T!~;S5vt09n4l3I=of=zN)yR)NKDeacE`bSqA&I?| z-&VV72}9f|J@4MQT)wrxmOdJlAaQLz?mzgL5;=W|@T2f+}L$kw0 za1opKE*Vx@_aVI3ZmeI8%-GCT{-|a<7~56}b*xor<2zHoB4V3)>q(&sCSrpm|I!f~ zV^(HU+0c9)09Ry-Gd8dSPt@q~qq{YIu`hw{i*JDKA3poVtIVIx6C5z)1-WDR5?6Cd z>7Ov);H9dN+qPN&H}Z2vc$d)hF%2oqJv6aquhQZOs2VGNzBi_Dop;6<)v*0?BmY}m zFl$gqVlOrFzmu;4;PTTw?yFKG*sG_VR;j&9{^oe!qXQ^4%!P)P*IrT-@zxy&b|2wxWOJnW{_XxFJ#~|cp8u}6Zk8v zYc^9iB^r!%L6U!I>te@~eYw@m1+uOTy~Y=FwT7{XQTk1aBJ2XR^zUJTSL@5PKb#EX zkvq?HT<0twJxs17)P#S)xZ-HJE4$>Q2@bdY#o;D6X>yV$2_J0`PWU>nIcmKdem*Yj zdF?=6YLRm3SKv06AWSs~1~*9ZFO3_I$Ho)JIv)^jhW8A$+UMIs432`6+5j}*tV``E#btg6Hr}Uz?6qIN zJE>Qxg}tW7wbBYGtVf=&OWl8kbuAQd#KvteE%+ z8k|>RoAj+@%}CB5BP!@4eZ>v(uQh!4+7}#K5_=hx;$U0H zg>lKzFby`T-09%oyk8?Y_xXEw`RFN z>YT{|&Iezp8fb>U&_#~SS&^<=-$P{dil8P?^WiHSvkH$aJ!<(CW7nelNJcamAA}_T z(mp8J^m%_Q_6f)be>U4gbN*hVnuxpYgU$jMi7Q46%?~MFEzAnZlzVx@H9INQQ@^>* z@>jO!M7KRX%TuUj4G0EQ^dNvOd?ss<)S(_1km4I=gll1#bC$zph-@qMSCnZ)%E@3Xft9Ng)bfEUm^S27~Qu zOF)OmPEv16KR99sw;-oxtz|H%0W|OzQ#eR${!zAsZ8EBl$80)f^m9y9U7SoRcRFSQI{zH`){NQlB?D_&!z@Y(qt3?{dcbead!vw z)=9m%ZH;GwX>*eT5aSE}uH1gb?WPC=?CH#m0OH3E3=Hu#ZfJKq9JSPPyubm+*(HXg z*Ps=xPuyYVtL93+gxYgPR5Llh%|v@U9JXWaR{$r# zpA9)^&);9vZQZ#q_cjRSaUKyPCGiZDZU~f2u@xp6x%Qw&W|)xZKfQMEAqfw8-T5tj zN0CqwDwuV^k7|LU;tEC!xN@=5^@4iBF%pib?PoQ>&(4oAQTDor()0(Q`-S+`K%+J2 z?WcY~9+gIxD2fw7iGxv1T7D=QtS!(j8oAD z1Ly7%$sNu;!J!W`xRv0%woh8Ywx0s??SmAwIVpE7H8^{**J@2wZc)er4=q=G&3=W~ z3R3H-2!rujNb)c5wV6($;`~ZxAm9RSWS9vCOVf-g#of1VY*1{ssD}b3EYDOm;ydWk z!^Bet5Y=$gAJ(AydH{i%cIEG*@fcOX0mmAqMUk73+$v|@#&)~%>Ja%+oD28o@q9`{ zFL@}=TQ0u>IH9Y;gYIB}gCzg*z?D~XT$Lfi1p)W7L5jxtD=Y@a2M@a$bF*~Lgmy7} z&9f(-wtvp5Y6-dLvAP{f?$`9!aCdTlw~KmOw+|7d!?|xfe$NVPMbD026%79mXtJTB z?Za-q4^ES+FZ$_2eu*D$YjhE-bt=J(P9T|RnviSl+_UNGo35z&W`%`8)){yL1HcZr zb{ofyg=|73iy#6xJ~I3=?+KpM+t~<%h=i6(N?>=Rbw>)C9%ld1q&LygCHdNmmc?&s#?=)$Is1yHRUgB69dtg&CF`ZKII2|Iqqd*UFZ z;{gtuTc*%cp>M&hRf)7~$oro62@J!1A~XzNGcCzj_J+~R$vI|leUy@_l7G3iY7Us% zm!FsVeQQ<3G+Ow0K326C6)sl&JY*so8{NjhTe0h{`Q~96>$$eK(RySAGIE;BhGR^4 z=9f_`%Of^}!L3zWq#vgzQo=m>u#!of)Hg-}DtnH8$%VHmV<2kYQ<<_c29AFZZ zki=eUt;#C|?GC9b;V=4s)Q9|a{qGZ|i*a5L?yw^K#QYGVmc%$ zfh_Ja;)lXU8x9;Uhqcgtu2<%d$8(^8g`^93I?$8a4iByv2$7?Y!%!H#stcjot7E^J zqN=qi4Q{Ys1{mkR+LXK1PGWU`h3bRAfK39)8y5;qr-!$05(+uk{))kVT?{)P+~NR| z{7Vn^_n$nz+xajLG}!;_%9QT>Y(#Q|+WV}wMl`dluG4NF++lo`NzgNm1fL(1jeCeS zKK}a+|9y7Jn_4F`1||S7@#^;!k_uyyse$@%ZeHXEG~odtOlk4)g43ktmQpNK&n6DC z(w8`gahMiCO3G9?XR={v){M{r{Wm;cBlkaEZ+tXQu`AWVTk7h4^J?E2>iaM!Sq7ld zy(tT<0_N?Sk9$=Pul(7CQ~I_{;Gq=}Ip5G}lY4yvH!rv!F}+wR8%Y<1E(gu`8kZPkRZnQ1d-V&@gZ-C zrDZ6*QOh^>wg`Zoe0GSwS@-h)S|0rV5~%LRHooxrEqzZm#1~BJ_eZrD$F>HeMLIJR z@>_SWRF2-en~#G&eGU}Gc{4S##kr@Klr0@1EBkvk1WJ8)ACa%UT6G80+Sp$7F1H>o z6L2*Lmi$v%@RjMJl-)E^J3nan5G$JbBN9AEL81>)cHQ7i&CmT6BgdPY98_bsY26=A z(IjII#UTPB{2p8Gk=E6^U$VZVr~pg`39{ICbYMWL8mRoJ2c^n)htQxpEb`F=J*?&( zHGg;fRe;;XCkyHp7;HIr+=H83wfJbb`!7P|SXz%~J~ZYug#(ujucg|WjqL!ESEVySzc&)qX1rAG`*N_j5nwd@8*U|$Ni(c2H(3c zc&V9h+w=U>(9ZTRmn{DTrVR3jwE&we_lfzkS$)Qvy6Tk(4}Uk#b=vrCYJ(FFOWTrw zl@6{*)@R`Jf;64ajD_jH2pFVUVzuwb2bXW<^S{bix#W;G3?|ft zB=%B6n$}bk05|e}$b)Bx*?6{EQP&xjL*^*Gu{43)(CTNtzT}6mdQ^!FG3V%t+14Vr z)3-3ta<+~A$+=3vrHbSv{L^o}&=Qp7ts*N^MA>FAwBTd4ifv<)0WbtJsB!*^RFMe$ z$q2X!50d=Lr;6IouCHq>R)FSi0lOnRZ7k#0^4M=@NrRYzeOO`ED#7BPF;Nl3~|RfrYKtR zyXGsBIWN-_U< zojT612yHibHdw%A&>+dbbZBcZhRFc0ehM)-{cq0XJX7 zGH#=vE(^%Chi3V1#=a<#(fCR*h^^{x4$0TCBYxx<@qcGMm+dw}$NyO#m z?qctJaKRq9`2tf?h;6Lk=<^^U{t%BHO^Q~2mENd54R5%04Hlt2G3KS_i)k7#)eb)| z_50?Fl1{XbZVuerDbl_$L5@w!D%%L0Kwo2@m6uuCFudD{9mCBqTuH**6rx^o2+I5Q zCjKei>7ch6XU~s%BZeQ@Aj!VZO{7Ct)Zv+n6}iPWYS{m?Jk4Lk>KWruJZ#WN>xMBP1%iLR7YEYjJRcASl#@ z%!u@wYy3VqGqYK#A@FPbXq&3tSIv)T)AA@rG^^uzMM~MwYxF25m)^^nnG=|G!p}?n zJ~IL~#i!1My90g$R z_9Qb46c+C4IS0@qT_5)juyyX4 ze(nNW97^9DAu+yDy_!RxWQ&3DUd^2QdIsQpHcz+2++4+MsG?Fz{QEcYC84!VaAW#3 z+K&REn~78rtjHZ%&^Z6I;l`cwpOxa<5dP;@Fl=7<#^dJeu#`LQpg%cV zm?g)|FV`8i#lH5>L2OT-t^Y~g`7M1%j;I(0Ols{%wIJVo4@L|9=D=IqOj3%hdIbzj zWN-s@9%R7RXd;_4vnHvAX;KlXqAiw*$joOA7mF0C&3 zQBTInJrEIeofAa5(Xx28){8d#<>LD=F@OSHu*45F_MbQ7hb4S_=_mHD48P_7iE}6j zJa~}yr*vLE(7#RCYk0rd#D4i$se^w3Uv_(g@S(|?1m=qT3CYFnUv~eBMEK(NAyKdD z;7(>_JHa!hbYiUPuQZ#Yqaium3;}Wrs8L7^GU7JoOv642uqzTbc4B*%T+?)=>Y!lo z&Leto3j$5mN?|h@S5@v#hbsv_s%9)v1dX?z9I@p}jFC!4IL-Zv1;Nev7;VrveeT{1 zB>9(L5G;D4#X3EO2PyFB7A}hw1s$)tW{R2X>RA)60)HMbt6t>ReuUOddn!@utVuO) zW}Cyd6tVR#9!%CU*YCDU1J_fr z1Oq1MLfg=D4Lfh&4(O{1{c@bZIl;~Q1RQV?+omH`y40m{I({Z2P<9oytYOo-`uPKX zhEHD^#UFY63gB+_-_sQa0~{pzmj(_21%6BHC7~h+xH(&GqrxT=3z59zIutY1F?G@` zHsHIrw-2)8%E;%p$eNYjnf3P3P)ldd@(;F{zez80>VN|W+?KC*&^^5f8O4s(T;D$O z-h%|u=T!z4)t^Q>i|HrYnSKRu;vMXh?qGm}B>(cjU6q(6%$ojM2=}uK)4B5#KQB~N zhm>oNaL)Xk$6}3U?qJ~>7VYXC-ka2gQ_WJDllUv9JJA9C(}3gBmlPoD`RNqW4%Q=1 zRWSTNpvhtlOMCz~HaJc2Sv8!J4Ft7?jCz?&cA>`KurATPNb&KZWP60~2s4iHO$rIl z{A{fJBem{`C%){sFtg+H)kIey^{w5qjRIz1m=}V?Dq^Yx&-%^f)6`FEcE=%XKFKaD z;DS4WZpV1b*auE}??;+@ufDp)Zc)P5XDL%~x@N2;Y-Wmnhzt0e}JV2Qru

37qB==G@B?i*%^Ze2JYlUsk0|RS8sDxV*;NG4-ZbXP{FE*b$ za&MQ5f8nBkX;t|?prsjEx>xwG!SK%)xsn(zk)=z`|3zAaErH3>Y1WbS9v%$&s$$NL zI6s%%!ViSvM=7BIuyfd=Egmgv{+3+%*$HL-{H47^opHRem7N2o(tXkWtH(%ZvbYVD zsMq*6KdPB--q+UqCx(0a{Y}YWQbXU9B%lXVNb;jvG)$g>(W2oIl}}W`etk~SXM(#! z3rbhTwu_akK6YGd=~k!Jn558Yz3T5I%|FQ%v#5P0sUsTIlG>vOnYA zwZDdVW8iWd{Kfac6p}y^d#Me6^Af5$+>dES6qJ>5y$@4-CoS;XD>v>~WB^rG9h)X6 z30Y#0iAzVTKHBind1>#?BACCsW%_tE_v}8n*)}2e#rmds4uyEgPABG$-n$;%h%P}*x@V&0!}48lw6Rr z)5Kv1AXK0UONE*CVhczNw@VU6&r%$g&~~f?cZe$FsY={aras{v1SDaTzp1} z(R@O{r;muHRns@G+CESHYHr;8A9vA%5;ZZ{ zT%J*Y1CC(x{!Z0ntZ~Efp3Q*n6`I~EuN6b3=0@?;e(i3#SNgvKIO!M9j6iyy8{a{a ze|g|Eg+V@_Ksbo#~rLQ2NRmcqsD7BsACD#+i9(T$Qgnhg@#Y zt9$+Y_~YlLe&3$g&;73JcG$J4^A`Q|F zf`BN}jiQ8pf$yOKiU5^)JVUwdTXKXV3Xr%V>5ncUEQ0ArOFr zvm6NATV4|%D<*wtWvx3p34Sfe@dZxx6cIIVgX3Gctd~myRv0lk&d#?%HK|xa$vWS6~1< z+-dTm_i%Ozc~bkc{9rYFc#P`UOC1;Qz|tTSS4`u{Jl6UOv~}|Jse_c&k6P2$%czz< z1o+6fj@JEGNQ3yd(F`9JuS#~ zQ}&XytU|O=$bCHb+kW>rS3ZS4;*5U;#sD!so~87^;mx=f2yp#5kW6N?`xRMP0wLML zFb?TJtT4pkacWw48f)?{BE8-kwZ>#q12Z)d(N6!DI{Z`mzhhN;NL`HBfml?$VX)+$ zLMe**4pc%Fq@AmGtaK#S7ZDjsXq9hjpfJ-@H@%na2#UeU>I14JTugKaSv7fmLsZQs zkhKuV7iz^j{9|^$tl^J#J{TFByNoEZKhypKsB?Fke5j*HnAwt`73MgYcL<9k>mYOo zw|USYO|(hsLe0G+q*$I#oA{txS%?o67*+LYSoE$CDtIja?*ZJu=ARIL*$BdC=laOW zRsep>r~CWV6t8>*T)*aHn&-BOfsZ8`R0x$^iejqHb+do}GGTo7pC4Uderx^b^%wa6 zY4cm=)8@DCKg(DdM*M~*q|3j>9KM#iq7uU+)E_h`ef5Y}T31Kqe`A7ne#`&AZ-44f zd9fhtW|H&OiJ^H)IimWF*kT@kwkLiM#th(CR@9;&$HTtG(L$=uZCV_4gTZ^EXBr)U zXLir{i}RiJVcp!_KJpxp1+R~gXoqY__NPP_QHL3uM7rGT+FOn8PeeC1XDm-7fINbv z7E!@)KJ`-Ua%<8JwEdcD-0}z-a>Hes+C0Cgs-4-(@CXMZxne-wh129i?GYk}qOhL8 zF@Qb7Me|A=$PGZ6*OlLIEf*Y+yaPQy`s1>GR{W%UbqpBW;1HP>onHH zt^8LfTCsFAwoFFI7v4IDqUPrAK4N3)9LOnEeV54PiPPM@l_5E&JY6=v1$={Y!%n+} zQr9fOhPyxpeAkPi*v)J*N|urVxwtzTG@0JhJ)SW%p%o>`bHzEr@G=beurKfxP+@qQ ze5egLPLzG|!w(Oz0e`_CDw@V8@LDU zAC0=@kSWuW%uRc5DVS*dlTq+Sw=`sp#vT;0YsBm}a8zl@X-u<8ev2j7P{mTA8R7Pz zoSMJb?%x*b$G&}W3ta#?T@nh)8UPFBt|8i2F~5PpQ>!BE?jvaV6hoKpXPAM^_^U;u z7S|J`zbsU?K(d_xb5nup^KmPk`f>K^K060Uz=-f?+|na?9pj(2*W%hnpQ6uedQXVi z3QRH9jFKJzJ`KhzuU<9DzG|V6RZh^nK3L?vGfXqls+@1)M+B$7S8`jffz|3l)Brgc~;j!gF|k z(~R$DLx4Gah>?q&hOAWG6b&W!*PmF)JoFn!E?}EAhiok%np?Cs^Rk@BOi^*sX-Y-c zvrxLeVmjVA^r4_Z>bd^q-!|*BO5FnaPG^X!3yJ{q-E*UunhS)C0?xv&pW>LY#?f)M z=B=d9uVCBO6(B~29Rbwpcf^o zgR@f}$NA`8Y>eFM`ZExrfg#gR{GzmC98~G%sDZc0m37JN8;FHrZbrsYUHv0qqwRvM z9V{$o^5pP37N4>+OvRh0(eI3`Ne3!g>I} zXf3t5F%~{Wz!FRnf1a}n8YV-YRxRFU*J0#YwrJTj+yBdG?S3>V*@<5(eAJ>JE#v)q zd~i@`4U{QIe!X#+^ftQpM$FzCI|zOQ~*6t%zTeA@GC0_ZNp044EGBE;UC2&L}MY&qeXy$o^0T z9VP9h#ntb5r%W!k5W(ylI0B-Iy`Ov$$3?08VCMia+n@bdTiYtoR z9J%}R`g;_sHTtyP>wKWG;Qj}OB=ORN+B|{A^sqB6PN~bCb$p&(FTz9-vL{~yO?sI| zo{4-#iOQTa=oAo>Jtl9v>L@*8pWLw(G-jZmWj_zqq<5hcpnABt)U!=`zq?N8hFI`Q z6FJYltxIE5-}$6D4%*}zYY(m6)+8BpcTTw3(vG82bFk$uy7l#$tN+tx@X;v*$Tt5{ z1fdoKZNofA&-AcJ*X!GE$rFpFXN(?)?ioJAj~*OAN6|V!vUYK)XQSw%%{N@g1}G+t zK#)m3{-Uy@r4XLsb)f0hSL9xwi6!Cn!stRJ5+{E<`aKTtQw^d=Pn>{E=`2GbHN6fe z2>??(2a^2kJ{OfS2_PiK+RC$fCIKmxw`b~MMLsSZ1upj8EBg}i`OcCSu^PV2A48$` z1LoJ^Kakw$bSA$zzLV!fVVqn5Sr+T4_p!>xlZs$)W+!qZGm_zk4EuP>%5?HKh-I>0 z1&7UP$SS8v>G%Ei^-y&(qd*nT<^7}~EC8*&Ba7 z|M#C~R9v*{Bm9n-^2LqOCr^g&lrpmVERwzX&L;5cKh5=HK>UM?vk#H`2XU4Jqq6JVbOZy-Y#fpk)QX&xP4#m(3G6;uBS-Q8a2CT(Yw7Q~ozAYGdq8n@1t>@ui%0~!;c3c^7 zHkk~Pi)S;|tg*gbLqF1X*VQ#C%2VdGVEvKR0K{ATRE!ex&Etom>}c|jF@juJ%4%`F zIgnko5!e`%GpDyNgEzR4WO<+-z-jWK=B-rAgcRW!ESNWB)_mhB`KTey;=%N(p&nU7-DP!tKOG(gdPZBb7xpp<3w;& zR|4{S=Rl(WFxt)`

A~hScnh_pQS+*e*c`KHCfw57C`*)JT(NYVadN?k#Xw{o(a4 z+ED3+%x1=?7!#YEn5sN8lb}zYyZBk;LJmww)yhkP@N!+44c>pSNgBcP<85J?1Qcvu zG3V+B@_^?+LO^EsC{HFG2#Ge@sA8hbXSRs#fC=>lco6aGW9vqtTd-BI-w?RVay9;7 z^P)N82gq#7(eJ@Fi3WN`-jVxi1dnXF{Y7Jh(E}ln<>lSaIBy>;{D)1$NTUSz?5DpT z7<}P~jClL%bs)cZ4kV%5{e-TnSwKkMGQUJebut)n&oh561-kw=PXBFP{`XzmYr``? zGz9VX|6ucC@8SfQY}8eLk2LY2s1v~sS$)WfjF&SYlp`j(C*f{t+bc6`Bz+kk5=nLa zHIRoqO+M5f@)=ukuTT0f-Y?qV6N0Qebg1MEsD&hSMDWQf4h-=>`C?YBazzrEeeg@O zS#2a%{-cFPjoTcu+Gy@T-~CxUB(mJ#O&||>4kWb^mP<@U=0HfS2S^DTLekTgN(iNU zD;Vk5pK66~k*kvz55w|%JFd3;p@kQFjxQYKs;{Z*p<=jO*OljZW6r8kdz?~95mPYR znICSMtv$kDduR?-qhV1JpgDS~REz{8$aq79^2htLnH*V(!UqrNb*kQv;*NV_;M&>p zmAxf=-)RL88=if^H(3MNsiU1re=mOv`Z1pJoA>j`lS_*F%h#)=_8;6O-AdEApK=*? ziXvJ%1Qa(;lMl6>Ha%9!u8UmY>W^|b^-qUbA)7f_ z;YzIQLo*-l^Bb&XCETlch{NSwbQ#Kr#%MJR6kJb}54G}jIX%3|;t>s2z9N(MM@z3P zQjwEQJ8ntxiZQVcA%I9*8}7V4o+P01Tj*opZ~SnO+eEC7XwLrC$9YF(HC!KPbQ{~e zUnE1Vkr8<7R!mqv5^YV#R8S*zT0KYG;XQpeh&m_q@E@p`k6*~s^cRe zjMre|L|cmBdrmrU_a@YbC}1*6WOABRg1C>ERG+MnV%iFZJLk7|_T4jRq+J_LBJL1V zOx__(=>Z}x;gb+COnXIu*uVlcc_Go&u@;ptcrQMrd8glN#Bt6lxD4Xd<$_$mxFOEG zPm>QlaWAJ$>=Y*4zyL1xHdKH~$FwVb5vrzY_9{%0jD?8>y-aN|GlHQhJZ_k?u+`7E zd(b5yHUPt*i%UJ*q$4t+hbh`A0*N*pQDj$~Lh9|wGY3$?T0xA!yQtDt0$HMjq#C0p zm<${I1}5`YD^8Sq+FGGNy_C4PmR|GwYugqPMV~0;|@@q8_5`wwQ=pvS3J5`W^iqF10>TcaX7gbQq67 z8;>pl{Z3pg9&)NIS$@)Pyd_6lx)wM?1_%OPc>~)^6GzGzR3(!uibno?Mt*6!`cKmj zrWsj3%D9DI25%U6bfZ9-+iCKl=IyQg^l^>>Gnh99T+Q7=8|hxIVUO;dXPCr&decE5 zlMQmY}8MD|4Q8~IY`z49>sBn)a@B9z zboqxXCk-OmqtLZtmun@cN(PfXUViS*vU&ea;>n(O7b6st$V7l)__kaBQ_+`)d*jbFP2?I==>g|G3^J(btnrIwsm(kzS}mR>t_G{Wy1KJKR>#_`7_%;um3;zKdADm z?pyBz3R~|Z9TJ*gPLY_5ed<@Y?+zN#xp!6WU?-h+KJ9;Fg7*9wQ{ex;|7kyEh`jLF z0^pI@_mO3jhhn*Ix!f03nJGjIbTrIdX-h@^(MxLKW1cLI_}@mmYiZVU>*7W0GZlc7 z73W29Yo-za#l4(+T@NVSB!x$Y_&Mb6xZ0#2)u^-F^a-9n*`L7ZANkw!4Rw}hI0>x! zS|I%}*&=ylQi`dN1G3{qb>eR@MRhgQy-6F!TR|QM|D35Ka#yj1pQt%pKM5#bX))tP zw?=*&kbLdEVID@TGk#%MU~%*8kzf+NxpeJ*82_gI7Xh2QEi%moqj>atW-dwX^&DCVq#bN z<}leZ5N{*9vV#gcdQDWx3Rh5?i(1sZwpl4T9z+JH!6&)W}CEu%!p+}t5jLzM^s-(azMkPaSd5hG-7H(YwpI}Iwoo9%GFKn zZUI$pT!tU~iur)@Jf)cxN&4}1{sZG_&O$hR{k-XiX-hcE37k!B&u`A?Y+Xj4r^zku zE&-6|ohBdpJa5KGfxybC1x(yU$BI3W^SoME&3-p~68)FuI-cAgdYbI6SjRP{wyNZp zQLZa*g+Bb3w=>)PXaSI6oh8rn09cqkFN(R7b^sI}g7qT%igbH!_ZED2>%KOk?roXH zh|-tr1X~91N0npz?d>i)O`L&DqK?!F>XRd7&1q%E+uEa;T(CjbYOaVI75rD4ZmMss z-~1PehDwf|0M7a>BxVEjInRqiFa~^1W?29A%G==Sbu7G?=e;uixg8^l9iT>AwC3fm z*++W}&+a&9IWto8@=LsXjm0797lbev=BoZTiM|a2rH8m{O?&NXvr+h%x6AmFgsm6dv$Zj|fZCfZPTvGf%*Kq7d6YulQd)V|Nbj^xDTIKRKvr z7Wbd@S0UIR_*e$wYKxp7ybKf8VkFxM1Tf)KDKDQJ!9aO6$BRdhQPcpm4M< zf30aP6j1r5isWio`F$D7Srugg&R%m&4GI>^Hp0J^=c1E_9?0sG(R459P94P$=VlYJ z9~oP`!_GhT`us8LwCq)#?^)#iXXkT|uOg#4pX^;2kRqIAgI1gT&=c&6Au94YkYwsv zMJ5$%0wIwo+2l4>n5RO({yx3PkNJuNJ4I(m?{QiD%#HA7DRYqVcX>XTE zq4^R$^R{ZvuZp8Y@Bjro*`MN#U&DS6|7G^OC+8UUhtg%T%FwN5Sz=rg4G$}zXzGP) zGy18tJT;wMF!RHX|A{+I2u;$=e6)IYui?s%;(^OBMIGFUeHZ`+Pm>RQG+oaXUiA{S z0DpxS?V89z{_=4dHc8$|!m){F4O?f61}4DiOS_>sDU2@_`PGt#qTv3vtX6D&Mlu8*iXJ@69?U84-@C{6nlBY z*&~{Xl|~Wm4>iP1ntbSBSEgZqTy;BWBL``w|A{3-*kPdEijJq`~ihS!v+ ztZpECE@64+qa7?fpk!Dy1*hiw&5gCxG)(uOsz`b_%xA-`oVwMpA6~=!Aenn`8Obo# zk5*lvX7OqAp-zTBM)ri<5+DR?A^+MlIgjR$Ec?z5H4xSe;m*yy=kgs% zW;maViz3PFyxG_?n*%U3`+N*^%R_-qTv+lUe#f9qt#W(MV$(2R@oni@e!v4>Wp|f3 zkMazmduq_lAzlEiyI)-D+2#-z-A%NDY^X8n*7*{>SquajRF=lmBxX_XDkn*(851?yv~7y_jb1XY#1UC64`bJk`{xVjcq|z zWKywvlL87t$?~~!n@>-UUZi&QC;efl7wvNboE9);ggKnjxe3pRnzpv!HH~qV2GJ*h zuEEC9o>*~oBSGgko5#lVhHbS(%)h3V7v843x|%f!G^scT642J6=1O-n5R%)Di5 zE3V@i(4B~*-R`W!3-Pwc#y444M9$e?CzB=%S-l-dhOXAbe(&ucx|w5vrLRCN$|66t zM{1x#^CP+w6AR>Qvx5+mH$*MnZ0TuI9#C1JvR_LkR`~j6Ds9@$x8t)w2SAPbw?z^j zM<3D(YY04C8K!FKtvlGlrQfKUsmL)vT(}QTM!f-wptEGtn*iOr)5QMegCUk)MIx{F zimWG)tnL6x+v5@MO$b zDnWM|g#@f*wr5iKpIDc-B?iv-$oD7B94*+sTskw!a{J)wH-~#1JiU%p3$2SVP`I|+tLncFQbBZ$=Rg8}1xK<$ z$}^xl@g%cNMkccA-Rm)R)e6aZ7QCi;->l|?vMY^ymv8o3(?;cjuR-ZTBhMkct~cGBCtwia3z2EEHYv1W%c zIXy6pK+S?Wj%uA@C)hO7yR{n2Ax37lIem`us(OQpWsOqnE z8_fLlQwXcBD)G1Z{u5BVM-!n4D1rdn0p~{1r3MgC6s_s-yVGP0#fe^i+96|4Rc9g? zlE}L1DBxQC;0+3z=wAWlqLl~0hB3<6W=v_G1XVGH5t{o^<}yzPVm$U&LL5_asmC!N zx@!KL!(FpdJwBKVH&5$H0mc{SMe*1x0RRQhbJj#SkKll?Hkb6iU2+nUZ{;HgB#qaV zSTjqD8bUq)Zl10ozpZI^=ff57-iR9!$Z)iqD~AKsP<$aUf}6kNZH{ktjS6!Pp4uv- zC6;!#g;)BCj=`offCW?L6ucV>X7sLnWpUTb?As_Nlj2LFHzZd21xI#xJ}OO@VZe6= zHi7^gz-i*4wqIl{deFm1!@thcUNj-3hFq(r%$v3b%)V0y9Sb;_^t(55H+T>I+d*&N zdShV)ec)o9w9k_Mm+&=CV6c9zL#cNGyU)QLtZd2|^CJ*r8Z> zcg10|enx{waWaTDTG)hKI>S6J-s$P!9wHgO!~Ng3`v0B@vP=U-tThH`lAasI_(y

L&(44g+ug+v^|E^M7 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 literal 0 HcmV?d00001 diff --git a/packages/lodestar/test/unit-mainnet/network/reqresp/encodingStrategies/sszSnappy/goerliShadowForkBlock.13249/streamed.snappy b/packages/lodestar/test/unit-mainnet/network/reqresp/encodingStrategies/sszSnappy/goerliShadowForkBlock.13249/streamed.snappy new file mode 100644 index 0000000000000000000000000000000000000000..4589528f61847ebb6283d8cf695275fc15b58b61 GIT binary patch literal 52357 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­+MBBXUw~ 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 nmnTM#&o(cMU?A { + id: string; + type: RequestOrResponseType; + bytes: Buffer; + streamedBody: Buffer; + body?: T; +} + +/** + * A real big bellatrix block from goerli-shadow-fork-2 devnet, which is expected to be + * encoded in multiple chunks (apart from the legngth prefix and the snappy frames header) + */ + +export const goerliShadowForkBlock13249: ISszSnappyTestBlockData = { + id: "goerli-shadow-fork-block-13249", + type: ssz.bellatrix.SignedBeaconBlock, + bytes: fs.readFileSync(path.join(__dirname, "/goerliShadowForkBlock.13249/serialized.ssz")), + streamedBody: fs.readFileSync(path.join(__dirname, "/goerliShadowForkBlock.13249/streamed.snappy")), +}; From 42b1761d32d249114d4c6450e6ab93fe76ff6a5a Mon Sep 17 00:00:00 2001 From: harkamal Date: Tue, 12 Apr 2022 17:02:58 +0530 Subject: [PATCH 02/11] cleanup comments --- .../network/reqresp/encodingStrategies/sszSnappy/testData.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/lodestar/test/unit-mainnet/network/reqresp/encodingStrategies/sszSnappy/testData.ts b/packages/lodestar/test/unit-mainnet/network/reqresp/encodingStrategies/sszSnappy/testData.ts index 3a59a3cd9bee..3de2ab4e6b0d 100644 --- a/packages/lodestar/test/unit-mainnet/network/reqresp/encodingStrategies/sszSnappy/testData.ts +++ b/packages/lodestar/test/unit-mainnet/network/reqresp/encodingStrategies/sszSnappy/testData.ts @@ -4,9 +4,6 @@ import path from "node:path"; import {bellatrix, ssz} from "@chainsafe/lodestar-types"; import {RequestOrIncomingResponseBody, RequestOrResponseType} from "../../../../../../src/network/reqresp/types"; -// This test data generated with code from 'master' at Jan 1st 2021 -// commit: ea3ffab1ffb8093b61a8ebfa4b4432c604c10819 - export interface ISszSnappyTestBlockData { id: string; type: RequestOrResponseType; @@ -17,7 +14,7 @@ export interface ISszSnappyTestBlockData = { From d7c767c6fad6de34ed53289f10c22d45abc17fcb Mon Sep 17 00:00:00 2001 From: harkamal Date: Fri, 15 Apr 2022 11:59:57 +0530 Subject: [PATCH 03/11] moving the chunking upstream --- .../reqresp/encodingStrategies/sszSnappy/encode.ts | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/packages/lodestar/src/network/reqresp/encodingStrategies/sszSnappy/encode.ts b/packages/lodestar/src/network/reqresp/encodingStrategies/sszSnappy/encode.ts index 5e0266654148..1bd27bf40325 100644 --- a/packages/lodestar/src/network/reqresp/encodingStrategies/sszSnappy/encode.ts +++ b/packages/lodestar/src/network/reqresp/encodingStrategies/sszSnappy/encode.ts @@ -4,13 +4,6 @@ import {createCompressStream} from "@chainsafe/snappy-stream"; import {RequestOrOutgoingResponseBody, OutgoingSerializer} from "../../types"; import {SszSnappyError, SszSnappyErrorCode} from "./errors"; -/** - * As per the snappy framing format for streams, the size of any uncompressed chunk can be - * no longer than 65536 bytes. - * - * From: https://github.com/google/snappy/blob/main/framing_format.txt#L90:L92 - */ -const UNCOMPRESSED_CHUNK_SIZE = 65536; /** * ssz_snappy encoding strategy writer. * Yields byte chunks for encoded header and payload as defined in the spec: @@ -37,11 +30,7 @@ export async function* writeSszSnappyPayload { const stream = createCompressStream(); - for (let startFrom = 0; startFrom < bytes.length; startFrom += UNCOMPRESSED_CHUNK_SIZE) { - const endAt = startFrom + Math.min(bytes.length - startFrom, UNCOMPRESSED_CHUNK_SIZE); - const bytesChunk = bytes.slice(startFrom, endAt); - stream.write(bytesChunk); - } + stream.write(bytes); stream.end(); return source(stream); } From 85202ac0aaf7cc893016ff4c1195c215b757606d Mon Sep 17 00:00:00 2001 From: harkamal Date: Wed, 27 Apr 2022 17:55:10 +0530 Subject: [PATCH 04/11] upgrade to the new snappy steam version supporting stream chunking --- packages/lodestar/package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/lodestar/package.json b/packages/lodestar/package.json index 0f0559a4bf18..b447769a5b39 100644 --- a/packages/lodestar/package.json +++ b/packages/lodestar/package.json @@ -76,7 +76,7 @@ "@chainsafe/lodestar-utils": "^0.36.0", "@chainsafe/lodestar-validator": "^0.36.0", "@chainsafe/persistent-merkle-tree": "^0.4.1", - "@chainsafe/snappy-stream": "5.0.0", + "@chainsafe/snappy-stream": "5.1.0", "@chainsafe/ssz": "^0.9.1", "@ethersproject/abi": "^5.0.0", "@types/datastore-level": "^3.0.0", diff --git a/yarn.lock b/yarn.lock index ccae6506c955..192a15f00872 100644 --- a/yarn.lock +++ b/yarn.lock @@ -493,10 +493,10 @@ resolved "https://registry.yarnpkg.com/@chainsafe/persistent-ts/-/persistent-ts-0.19.1.tgz#53d03aa31ef7698b09327f74eef01e286b97bae3" integrity sha512-fUFFFFxdcpYkMAHnjm83EYL/R/smtVmEkJr3FGSI6dwPk4ue9rXjEHf7FTd3V8AbVOcTJGriN4cYf2V+HOYkjQ== -"@chainsafe/snappy-stream@5.0.0": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@chainsafe/snappy-stream/-/snappy-stream-5.0.0.tgz#87dfb8dd6e5a20c7e982700974fd59941f5a96c4" - integrity sha512-E5Y9KsyTMjXGgoLl2sIetiIpztum4NUznNDAYa+DoN20HjGNUv4ZSB5rnQrlWKVq6POnkL6vPTZC2TLYosR0wA== +"@chainsafe/snappy-stream@5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@chainsafe/snappy-stream/-/snappy-stream-5.1.0.tgz#ba1a089615ded69b67840de3f82d913372c8e5d8" + integrity sha512-l6GCYv/CvXvt/6pWoS376R2qpRX4vG0RBrtzb6dUmyqJf9aJ8KzZrcQJV20VxY935arEEqC5zhA1QYbYGdM0hw== dependencies: "@chainsafe/fast-crc32c" "3.0.0" bl "^1.0.0" @@ -7063,7 +7063,7 @@ libnpmaccess@^4.0.1: npm-package-arg "^8.1.2" npm-registry-fetch "^10.0.0" -libnpmpublish@4.0.0, libnpmpublish@^4.0.0: +libnpmpublish@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/libnpmpublish/-/libnpmpublish-4.0.0.tgz#ad6413914e0dfd78df868ce14ba3d3a4cc8b385b" integrity sha512-2RwYXRfZAB1x/9udKpZmqEzSqNd7ouBRU52jyG14/xG8EF+O9A62d7/XVR3iABEQHf1iYhkm0Oq9iXjrL3tsXA== From 2d98f698b2eced10527ca47c6ba39c533562f034 Mon Sep 17 00:00:00 2001 From: harkamal Date: Wed, 27 Apr 2022 18:14:56 +0530 Subject: [PATCH 05/11] switch to async version to match the chunks --- .../src/network/reqresp/encodingStrategies/sszSnappy/encode.ts | 2 +- packages/lodestar/types/snappy-stream/index.d.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/lodestar/src/network/reqresp/encodingStrategies/sszSnappy/encode.ts b/packages/lodestar/src/network/reqresp/encodingStrategies/sszSnappy/encode.ts index 1bd27bf40325..7713d28fb9d5 100644 --- a/packages/lodestar/src/network/reqresp/encodingStrategies/sszSnappy/encode.ts +++ b/packages/lodestar/src/network/reqresp/encodingStrategies/sszSnappy/encode.ts @@ -29,7 +29,7 @@ export async function* writeSszSnappyPayload { - const stream = createCompressStream(); + const stream = createCompressStream({asyncCompress: true}); stream.write(bytes); stream.end(); return source(stream); diff --git a/packages/lodestar/types/snappy-stream/index.d.ts b/packages/lodestar/types/snappy-stream/index.d.ts index f411a2059f3e..c984683d5238 100644 --- a/packages/lodestar/types/snappy-stream/index.d.ts +++ b/packages/lodestar/types/snappy-stream/index.d.ts @@ -2,5 +2,5 @@ declare module "@chainsafe/snappy-stream" { import {Transform} from "node:stream"; export function createUncompressStream(opts?: {asBuffer?: boolean}): Transform; - export function createCompressStream(): Transform; + export function createCompressStream(opts?:{asyncCompress?: boolean}): Transform; } From 105300e29c57f6375dc2100e212d5764e0932dd1 Mon Sep 17 00:00:00 2001 From: harkamal Date: Wed, 27 Apr 2022 19:24:08 +0530 Subject: [PATCH 06/11] fixing the uncompress test --- .../sszSnappy/snappy-frames/uncompress.test.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/lodestar/test/unit/network/reqresp/encodingStrategies/sszSnappy/snappy-frames/uncompress.test.ts b/packages/lodestar/test/unit/network/reqresp/encodingStrategies/sszSnappy/snappy-frames/uncompress.test.ts index 113914652846..96e6c0ced33d 100644 --- a/packages/lodestar/test/unit/network/reqresp/encodingStrategies/sszSnappy/snappy-frames/uncompress.test.ts +++ b/packages/lodestar/test/unit/network/reqresp/encodingStrategies/sszSnappy/snappy-frames/uncompress.test.ts @@ -27,10 +27,12 @@ describe("snappy frames uncompress", function () { const decompress = new SnappyFramesUncompress(); const testData = Buffer.alloc(100000, 4).toString(); + let result = Buffer.alloc(0); compressStream.on("data", function (data) { - const result = decompress.uncompress(data); - if (result) { + // testData will come compressed as two or more chunks + result = Buffer.concat([result, decompress.uncompress(data) ?? Buffer.alloc(0)]); + if (result.length === testData.length) { expect(result.toString()).to.be.equal(testData); done(); } From a2895f49a11595bcfdc42a47613757fd3798a39b Mon Sep 17 00:00:00 2001 From: harkamal Date: Thu, 28 Apr 2022 13:01:48 +0530 Subject: [PATCH 07/11] update the package fix --- packages/lodestar/package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/lodestar/package.json b/packages/lodestar/package.json index b447769a5b39..ccb74e2efa74 100644 --- a/packages/lodestar/package.json +++ b/packages/lodestar/package.json @@ -76,7 +76,7 @@ "@chainsafe/lodestar-utils": "^0.36.0", "@chainsafe/lodestar-validator": "^0.36.0", "@chainsafe/persistent-merkle-tree": "^0.4.1", - "@chainsafe/snappy-stream": "5.1.0", + "@chainsafe/snappy-stream": "5.1.1", "@chainsafe/ssz": "^0.9.1", "@ethersproject/abi": "^5.0.0", "@types/datastore-level": "^3.0.0", diff --git a/yarn.lock b/yarn.lock index 192a15f00872..415e519ea887 100644 --- a/yarn.lock +++ b/yarn.lock @@ -493,10 +493,10 @@ resolved "https://registry.yarnpkg.com/@chainsafe/persistent-ts/-/persistent-ts-0.19.1.tgz#53d03aa31ef7698b09327f74eef01e286b97bae3" integrity sha512-fUFFFFxdcpYkMAHnjm83EYL/R/smtVmEkJr3FGSI6dwPk4ue9rXjEHf7FTd3V8AbVOcTJGriN4cYf2V+HOYkjQ== -"@chainsafe/snappy-stream@5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@chainsafe/snappy-stream/-/snappy-stream-5.1.0.tgz#ba1a089615ded69b67840de3f82d913372c8e5d8" - integrity sha512-l6GCYv/CvXvt/6pWoS376R2qpRX4vG0RBrtzb6dUmyqJf9aJ8KzZrcQJV20VxY935arEEqC5zhA1QYbYGdM0hw== +"@chainsafe/snappy-stream@5.1.1": + version "5.1.1" + resolved "https://registry.yarnpkg.com/@chainsafe/snappy-stream/-/snappy-stream-5.1.1.tgz#9f3c79fd936b591d4a79d1801ffb582df54f1858" + integrity sha512-wy1c0RLUttVYMQHN/zs473LIzZ6NEL2xG3T8vJp+Ag99H/lQldnwYY6aKGcMrt6hEhndRx0a4NaUxr70MTzsLg== dependencies: "@chainsafe/fast-crc32c" "3.0.0" bl "^1.0.0" From 3f5114e5dbbf950331a298e20fff0d52efc5af5d Mon Sep 17 00:00:00 2001 From: harkamal Date: Thu, 28 Apr 2022 16:22:22 +0530 Subject: [PATCH 08/11] shift to sync compress version as it is almost 2x faster --- .../encodingStrategies/sszSnappy/encode.ts | 7 ++++++- .../encodingStrategies/sszSnappy/encode.test.ts | 4 ++-- .../encodingStrategies/sszSnappy/testData.ts | 15 +++++++++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/packages/lodestar/src/network/reqresp/encodingStrategies/sszSnappy/encode.ts b/packages/lodestar/src/network/reqresp/encodingStrategies/sszSnappy/encode.ts index 7713d28fb9d5..93f677bae43b 100644 --- a/packages/lodestar/src/network/reqresp/encodingStrategies/sszSnappy/encode.ts +++ b/packages/lodestar/src/network/reqresp/encodingStrategies/sszSnappy/encode.ts @@ -29,7 +29,12 @@ export async function* writeSszSnappyPayload { - const stream = createCompressStream({asyncCompress: true}); + /** + * Use sync version for compress as it is almost 2x faster than async version + * and most payloads are "1 chunk" and 100kb payloads (which would mostly be + * big bellatrix blocks with transactions) are just 2 chunks + */ + const stream = createCompressStream({asyncCompress: false}); stream.write(bytes); stream.end(); return source(stream); diff --git a/packages/lodestar/test/unit/network/reqresp/encodingStrategies/sszSnappy/encode.test.ts b/packages/lodestar/test/unit/network/reqresp/encodingStrategies/sszSnappy/encode.test.ts index eaf279ac6abb..632c25efefe2 100644 --- a/packages/lodestar/test/unit/network/reqresp/encodingStrategies/sszSnappy/encode.test.ts +++ b/packages/lodestar/test/unit/network/reqresp/encodingStrategies/sszSnappy/encode.test.ts @@ -23,7 +23,7 @@ describe("network / reqresp / sszSnappy / encode", () => { const testCases = [sszSnappyPing, sszSnappyStatus, sszSnappySignedBeaconBlockPhase0]; for (const testCase of testCases) { - const {id, type, chunks} = testCase; + const {id, type, syncChunks} = testCase; it(id, async () => { const body = type === ssz.phase0.SignedBeaconBlock @@ -36,7 +36,7 @@ describe("network / reqresp / sszSnappy / encode", () => { ), all ); - expectEqualByteChunks(encodedChunks, chunks); + expectEqualByteChunks(encodedChunks, syncChunks); }); } }); diff --git a/packages/lodestar/test/unit/network/reqresp/encodingStrategies/sszSnappy/testData.ts b/packages/lodestar/test/unit/network/reqresp/encodingStrategies/sszSnappy/testData.ts index 96974ddb1501..ad6d14d26100 100644 --- a/packages/lodestar/test/unit/network/reqresp/encodingStrategies/sszSnappy/testData.ts +++ b/packages/lodestar/test/unit/network/reqresp/encodingStrategies/sszSnappy/testData.ts @@ -9,7 +9,10 @@ export interface ISszSnappyTestData { id: string; type: RequestOrResponseType; body: T; + /** chunks expected in an async compress version of snappy stream */ chunks: Buffer[]; + /** chunks expected in a sync compress version of snappy stream */ + syncChunks: Buffer[]; } export const sszSnappyPing: ISszSnappyTestData = { @@ -21,6 +24,7 @@ export const sszSnappyPing: ISszSnappyTestData = { "0xff060000734e61507059", // snappy frames header "0x010c00000175de410100000000000000", // snappy frames content ].map(fromHexString) as Buffer[], + syncChunks: ["0x08", "0xff060000734e61507059010c00000175de410100000000000000"].map(fromHexString) as Buffer[], }; export const sszSnappyStatus: ISszSnappyTestData = { @@ -38,6 +42,9 @@ export const sszSnappyStatus: ISszSnappyTestData = { "0xff060000734e61507059", // snappy frames header "0x001b0000097802c15400da8a010004090009017e2b001c0900000000000000", ].map(fromHexString) as Buffer[], + syncChunks: ["0x54", "0xff060000734e61507059001b0000097802c15400da8a010004090009017e2b001c0900000000000000"].map( + fromHexString + ) as Buffer[], }; export const sszSnappySignedBeaconBlockPhase0: ISszSnappyTestData = { @@ -71,6 +78,10 @@ export const sszSnappySignedBeaconBlockPhase0: ISszSnappyTestData = { @@ -92,4 +103,8 @@ export const sszSnappySignedBeaconBlockAltair: ISszSnappyTestData Date: Thu, 28 Apr 2022 16:27:53 +0530 Subject: [PATCH 09/11] update comment --- .../reqresp/encodingStrategies/sszSnappy/encode.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/lodestar/src/network/reqresp/encodingStrategies/sszSnappy/encode.ts b/packages/lodestar/src/network/reqresp/encodingStrategies/sszSnappy/encode.ts index 93f677bae43b..8bc238d144db 100644 --- a/packages/lodestar/src/network/reqresp/encodingStrategies/sszSnappy/encode.ts +++ b/packages/lodestar/src/network/reqresp/encodingStrategies/sszSnappy/encode.ts @@ -30,11 +30,14 @@ export async function* writeSszSnappyPayload { /** - * Use sync version for compress as it is almost 2x faster than async version - * and most payloads are "1 chunk" and 100kb payloads (which would mostly be + * Use sync version (default) for compress as it is almost 2x faster than async + * one and most payloads are "1 chunk" and 100kb payloads (which would mostly be * big bellatrix blocks with transactions) are just 2 chunks + * + * To use async version (for e.g. on big payloads) instantiate the stream with + * `createCompressStream({asyncCompress: true})` */ - const stream = createCompressStream({asyncCompress: false}); + const stream = createCompressStream(); stream.write(bytes); stream.end(); return source(stream); From 66f1c3f80a6daba000e20267bddd9b6ed9ff3cc3 Mon Sep 17 00:00:00 2001 From: harkamal Date: Thu, 28 Apr 2022 16:47:56 +0530 Subject: [PATCH 10/11] lint --- .../network/reqresp/encodingStrategies/sszSnappy/encode.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/lodestar/src/network/reqresp/encodingStrategies/sszSnappy/encode.ts b/packages/lodestar/src/network/reqresp/encodingStrategies/sszSnappy/encode.ts index 8bc238d144db..b59c85f1f29d 100644 --- a/packages/lodestar/src/network/reqresp/encodingStrategies/sszSnappy/encode.ts +++ b/packages/lodestar/src/network/reqresp/encodingStrategies/sszSnappy/encode.ts @@ -30,11 +30,11 @@ export async function* writeSszSnappyPayload { /** - * Use sync version (default) for compress as it is almost 2x faster than async + * Use sync version (default) for compress as it is almost 2x faster than async * one and most payloads are "1 chunk" and 100kb payloads (which would mostly be * big bellatrix blocks with transactions) are just 2 chunks - * - * To use async version (for e.g. on big payloads) instantiate the stream with + * + * To use async version (for e.g. on big payloads) instantiate the stream with * `createCompressStream({asyncCompress: true})` */ const stream = createCompressStream(); From 23b08828da067eb18743d8ff73b34c2fd307d406 Mon Sep 17 00:00:00 2001 From: harkamal Date: Thu, 28 Apr 2022 19:25:56 +0530 Subject: [PATCH 11/11] flip async and sync chunks --- .../sszSnappy/encode.test.ts | 4 ++-- .../encodingStrategies/sszSnappy/testData.ts | 20 +++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/lodestar/test/unit/network/reqresp/encodingStrategies/sszSnappy/encode.test.ts b/packages/lodestar/test/unit/network/reqresp/encodingStrategies/sszSnappy/encode.test.ts index 632c25efefe2..eaf279ac6abb 100644 --- a/packages/lodestar/test/unit/network/reqresp/encodingStrategies/sszSnappy/encode.test.ts +++ b/packages/lodestar/test/unit/network/reqresp/encodingStrategies/sszSnappy/encode.test.ts @@ -23,7 +23,7 @@ describe("network / reqresp / sszSnappy / encode", () => { const testCases = [sszSnappyPing, sszSnappyStatus, sszSnappySignedBeaconBlockPhase0]; for (const testCase of testCases) { - const {id, type, syncChunks} = testCase; + const {id, type, chunks} = testCase; it(id, async () => { const body = type === ssz.phase0.SignedBeaconBlock @@ -36,7 +36,7 @@ describe("network / reqresp / sszSnappy / encode", () => { ), all ); - expectEqualByteChunks(encodedChunks, syncChunks); + expectEqualByteChunks(encodedChunks, chunks); }); } }); diff --git a/packages/lodestar/test/unit/network/reqresp/encodingStrategies/sszSnappy/testData.ts b/packages/lodestar/test/unit/network/reqresp/encodingStrategies/sszSnappy/testData.ts index ad6d14d26100..9d77c94c8386 100644 --- a/packages/lodestar/test/unit/network/reqresp/encodingStrategies/sszSnappy/testData.ts +++ b/packages/lodestar/test/unit/network/reqresp/encodingStrategies/sszSnappy/testData.ts @@ -10,21 +10,21 @@ export interface ISszSnappyTestData { type: RequestOrResponseType; body: T; /** chunks expected in an async compress version of snappy stream */ - chunks: Buffer[]; + asyncChunks: Buffer[]; /** chunks expected in a sync compress version of snappy stream */ - syncChunks: Buffer[]; + chunks: Buffer[]; } export const sszSnappyPing: ISszSnappyTestData = { id: "Ping type", type: ssz.phase0.Ping, body: BigInt(1), - chunks: [ + asyncChunks: [ "0x08", // length prefix "0xff060000734e61507059", // snappy frames header "0x010c00000175de410100000000000000", // snappy frames content ].map(fromHexString) as Buffer[], - syncChunks: ["0x08", "0xff060000734e61507059010c00000175de410100000000000000"].map(fromHexString) as Buffer[], + chunks: ["0x08", "0xff060000734e61507059010c00000175de410100000000000000"].map(fromHexString) as Buffer[], }; export const sszSnappyStatus: ISszSnappyTestData = { @@ -37,12 +37,12 @@ export const sszSnappyStatus: ISszSnappyTestData = { headRoot: Buffer.alloc(32, 0xda), headSlot: 9, }, - chunks: [ + asyncChunks: [ "0x54", // length prefix "0xff060000734e61507059", // snappy frames header "0x001b0000097802c15400da8a010004090009017e2b001c0900000000000000", ].map(fromHexString) as Buffer[], - syncChunks: ["0x54", "0xff060000734e61507059001b0000097802c15400da8a010004090009017e2b001c0900000000000000"].map( + chunks: ["0x54", "0xff060000734e61507059001b0000097802c15400da8a010004090009017e2b001c0900000000000000"].map( fromHexString ) as Buffer[], }; @@ -73,12 +73,12 @@ export const sszSnappySignedBeaconBlockPhase0: ISszSnappyTestData