From 42abd8cf6d5d5d5085560bb5ba0214c69c45fc76 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 26 Sep 2024 17:55:32 -0400 Subject: [PATCH 01/10] Add arguments_contains() and last_irreversible_block_id() to libtester --- libraries/testing/include/eosio/testing/tester.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libraries/testing/include/eosio/testing/tester.hpp b/libraries/testing/include/eosio/testing/tester.hpp index b963a5a47b..86dd17e6f4 100644 --- a/libraries/testing/include/eosio/testing/tester.hpp +++ b/libraries/testing/include/eosio/testing/tester.hpp @@ -521,6 +521,13 @@ namespace eosio::testing { return {cfg, gen}; } + static bool arguments_contains(std::string arg) { + auto argc = boost::unit_test::framework::master_test_suite().argc; + auto argv = boost::unit_test::framework::master_test_suite().argv; + + return std::find(argv, argv + argc, arg) != (argv + argc); + } + // ideally, users of `tester` should not access the controller directly, // so we provide APIs to access the chain head and fork_db head, and some // other commonly used APIs. @@ -529,6 +536,7 @@ namespace eosio::testing { block_handle fork_db_head() const { return control->fork_db_head(); } chain_id_type get_chain_id() const { return control->get_chain_id(); } + block_id_type last_irreversible_block_id() const { return control->last_irreversible_block_id(); } uint32_t last_irreversible_block_num() const { return control->last_irreversible_block_num(); } bool block_exists(const block_id_type& id) const { return control->block_exists(id); } From b84f0d7439804f30c11bffc8531f13c5721f6c6a Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 26 Sep 2024 17:55:50 -0400 Subject: [PATCH 02/10] Create initial consensus_blockchain data --- .../consensus_blockchain/blocks.index | Bin 0 -> 128 bytes .../test-data/consensus_blockchain/blocks.log | Bin 0 -> 39307 bytes unittests/test-data/consensus_blockchain/id | Bin 0 -> 32 bytes .../test-data/consensus_blockchain/snapshot | Bin 0 -> 2154795 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 unittests/test-data/consensus_blockchain/blocks.index create mode 100644 unittests/test-data/consensus_blockchain/blocks.log create mode 100644 unittests/test-data/consensus_blockchain/id create mode 100644 unittests/test-data/consensus_blockchain/snapshot diff --git a/unittests/test-data/consensus_blockchain/blocks.index b/unittests/test-data/consensus_blockchain/blocks.index new file mode 100644 index 0000000000000000000000000000000000000000..47202d52afed315db358f3dcc809565da722f855 GIT binary patch literal 128 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 N`I0?w7JUT7e*v#iN1y-z literal 0 HcmV?d00001 diff --git a/unittests/test-data/consensus_blockchain/id b/unittests/test-data/consensus_blockchain/id new file mode 100644 index 0000000000000000000000000000000000000000..60026cda7bdc002a9e40596422fe6c343717e54b GIT binary patch literal 32 ocmZQzU=S{fx2@dkdxcY$Blv>AVuhbU4l~3BS30Fz-KdlR0H9h5-2eap literal 0 HcmV?d00001 diff --git a/unittests/test-data/consensus_blockchain/snapshot b/unittests/test-data/consensus_blockchain/snapshot new file mode 100644 index 0000000000000000000000000000000000000000..cbc66335bd013d2ae5ec0f9ae6c5eb4e7eaf3a8b GIT binary patch literal 2154795 zcmeF%cbHvO-7xG^rX`cWkkApBM7k{r7?2`4AiXGEK%7i6C&?s}naRu~B(wyKij)Tg z5do=Er3yTXN>?n1f;16P5y65W_(&Cz@3;0j)51WW_v8KJ`>yMrTr+3ywO75@+H0@9 zPCiw;-=uslmzxy7=_ehhpK@1kd)Kzx&YaWQ-dX)<>FsRo?w!-s*D|Nv+E(t#HAK8~ z>$B+ZkZwjt*UWh>y?w2H2$qP3)>%hwvzjgEp zn{7I3yB+q*a(i~tLD}c11?&9n!?S*~>!~j;d2Z`fW<2)v`(FJ*`~6@2N7v{6);*<~@;eSuS75)sKp! zXm)Zac|-u9=dXTE&EM%VB1fh8CGVe2c` zJ^i!KZ@l^WKb!l?8B_N9(s>{I$Na+%7`VB|N4)EZ{BTo{YUR!yW_NNibI%Qj)_&%a@rQi9 z^U8z2dgQpvrmwa8;xAnK@O`W9d-Okde>`{9F1w$%#hkVF_}jrR|1S64Tz=p2$3FhY z3wM9z{Mnzp_vFVuaNF7&EZBFm9Y6Pnn~yl_-osv6^_FuVI{WDI_MbRy@!bdR{O{L3 zH|d@)+`3B34u5a@^DEmgy0fsyPnJIY#;gB4rJ=d*=9yE*K782;%s+PmLl_q=k!IbXl{k4q-s zS{l81-)8fEHtmvq_qcoh=;`}yH}`L!-|xY;rxz@pH1GIt9Cg?m+wJy?Cr-ZXBY*zJ zSskBw=<L4~xyRPLwD#Hyb~vqE_r>lDA3bfa({JAJ z*b@$$dU)aPZD)48aN;#v+&O0FTOYh+=2vc-wfdX8e`TZfx8G&m8(w*HwNan`!A_HU zXROSOKUbgr$nXAp>~nCckjDt*LU|_xAB$B zHoN(>TR-{oCNJ!~+6T)!-*W1Wn{E5y`kuu4I z`MlY;?0m&0TP#26#Y@la{K!?We0txT3u&aMn>If>{$#_xkV2N6^v5%PI_no7-+KAa zw%g>wGmby>xBtD%kES3Y>^)I-ndpEFXX?{>#FL|%W`;La~z_~$SG=*8c@vfqQ7wjcksul@3=)33SW z!QY;A;3u9~zpZ&lUb%caDaLR5sab1QduMA$`%&ed*4E~>a_`KZ_U^v+uFn1x(@#F} zlixgavxcu;^qCuGT(`v$pDZ1DTZg<@-tGJk>{9saI*)AL zGHJ=df7@~WC%)dY?zxZOH0?k8{`)8OTfDGfwdPw-I{%m_?wNM!MUNkP=$Fsj@a(m> z`pCjtcYms7z4Mn}zT3CYIQW*&77sb#$D_Y~z&>?DDll`z3S7GHb+0|~*3CC;`RMpl zwm$CR3;K3D`KpKkVFi|^k1i~oI9>r16G@3`adS6s1I&25Lz{aya) z9bf$MQ`@hf8++FyOHbMHx~u+n#*gm*#`a%cbN*|mj_d5({MGzX<5&5|&KnkHT)*0o z3bc(_fq#zs%6FgXz5kgbCUzb9?MLqU{B7&sd(5``%>VY*m)@9rwdQD z7c-uH?9GkuT79k6U%GeWL;mwv?Y3L}e!}F>>~!l1&A)lP?=zR5m3#I(tG@Zq<_GRw ze!!)h{Q03`t6#X zFP!zS_E&y-;@qb`H+8$auYIhVGJPEJ@|LGxcfx9ON?V*UZt=rC^B>spk58WSg>T%y z+TCN`c;Cre{=OK)G+%wJ<%)+--uA>>U%lW{f125~>ne|QZt;PazxUk(H@|R)hnrU2 zYsTbXU-Gjr9P_hDkNn}5SFhOl_T1$69nn=dYps|1uKUSpi`F}CV(*FLA1^)7wBzAF zx$2FlPXETC*UsK$_WJ+x$AuTodiurPPF#BV?0=0fZZfmxfgeq|?_Zbx&$T~T^R-JK z?7jVu$L?Qf+`R9&T_;_)$F+y8>^W8}&2Bq(m#-f8$fAEAbK>zGg*~p_{I#opc*bk5 zulMh7e)XDVXH88vd;Ij@NW-7(tutqKE$r-T>6$UOJhQJ7GqHxjU&pUfjoUh-{Ueh< zJSD$Y^?BYtyR*G>c1!ERzByez?R`roE^6&*Z;f2u;d;xWN$+cjOj_o&_Rh%_YP*i? zEceuOw$3ltq>#p$bILR4^)8%0<)c#@T4(mPFG}l${3^4`t$ho7$}Mf}v&+4GLt~8^ zC^}a&s&7tDIhG|IZFLLVJNverQZui-q<2jGX*sgoK6_5z;YUQKSu1CLS+etzrX zDphB>uVrCx>+Et?_o-X0+t=DNJHjd@4_s~Op4nGz-8w08Ur%diZ<3033`D9%*kDF$ zZ@DEJ`mV8>29gCt`N-BK)zt5w+11%sUfkC*tEZggdn?0ZFm~s{`TyIfZRO5t)FCaN z*}ZT`i?^IIyu|}o->t<1k*c|`GrzraSYua=u=a{(9qqHqeeLrr>RV3PpshTs+|yHT zi(D4Bloxlm_q1lVN49sibsbqPW{nkdX)AXOxUHEkws&^4ca~eK9n%}ns%p};-hQ>M z+}$@PyF7Vn#xpRaTZUe0oY~qrv)qvtl`E`LIqSdqnpPanb*cXCZ9{LB(UCO9UCKRI zsIT4#*}XSw5coqU^fLeU(*y>Q7tZKtpV<;OT=jaf zyQ{l;*ff}DcUQz(^0pf%G8l-{yT-ubU=oGTRLWN48?>N0t1L-^0jnp!ig zsWmgZ+RBv)r*BDj<*2czykKE_PkDa1v#;XO8TUbDqR7?M&+LiWr>iT!M}3-?CQsR>Awv4n5UZWBq_5ojw%&`GF|wjimu;mJ42LcCLIoOj&bh_TrK0jvU=!v0Yc2vxwEty_z zn8w&i6H{dfR0GnzKQy2|@=CqGLPm9q=BJTRo4RJ3QH$m;ikUfP)5>`^Tq;!=6Uhe# zWiJ1=@%*-c==Q#BvhU61>naB$KL=99x_jCet)Nif-rJIbD>aEB6Op>wBD03xcuck} z>?p53&|w3;828A+H1|}-esLJtNMnEW!tS={xe@M^A%m&XRndh08>A-19~>KvLmrm7 zLPK`eTb@~+@`jJR)na9_#d*(9nKJl%&)xc^Eq3|*<)vXWTyEOW9>4OMOZFT(Yemuz z%`0AU^5D&#n|8su6WeY%H+p~Ij*VDPK6vyamk!*3ryn@=H|4f#zBhcRMzo8{^RM~d zz_5&f+$}S2yt{u)=5oK-_j_}0ynE;vj40DKKIz802gXwOBS-#n@9*4r_wdn?%ia0l zXAZdO?jb`UQcnN=;WuR|v(AoyZGIU6gB_cieCJ=EdU$9LW(*zsKQgqR($e*!)`y;$ zTx_4ZRlKzgtfylA`@dL#<=<^Jlbd$RQHAQVFPH1S2)*x^nXrjc;)5NzBl~yk_S7B^(Sud>^eW}_|KnqedD&LUEd)s)qD zmKFBmW_NVWXzhqOqAQ*VeM^RsN5ZBo@n5q3YRHX=vzH>D)#I}*ey5Es=F+tn_b6oN zO{?T`pN`&GcEEOVwINrNt4ps_xlimgY02|jZ?Vtgjjw%u+e7zxY1Fe<-gUr%`+et; zd*|+O)Yk3eB4WIf$8U4|rUdD8;CxyHOv^V#zHdbEyj9~*{6t{(Gn^vY(bqMztD~|@ z*x#D9R<_rcM$pRk+fsd2wx^QftZd&b#aY?jO^UO!{jC&dWqVX9&dT<=Qk<3TC8jtl z+b>FSR<fZ1#X;|!j=uKlQBNGj#hLTF`({mv zgSPfX5vzL8zGZz&OL;+D85^IA`(gpxHf!ivZ#s)CXSFYm3+K!=h zYaf%PSlHQ{5)GWBbOR?T>5!A&p(lOqjgdh|S8HEed*7`7dWW5*n9<;P-<~xkefCv8<8>)(WXFJ893{7i(~;tY*8Hxv3grBS9TmTHkkNLQ zXIJuxrD+zocj1hP5{>KYS=c!<8aivr;7M;*)WXyaSr;v=E?LFgKdwb*A(Gt&{ zu2}e{SGT7Ap!V+a{IfeDpDQo(8)Vx`X(yzA%cr_tJ}P^;->`Cd=vKrFEk#)COt*g~n?9!z8U z1JcgH=(ZUxaeK7HTC6b+;}s!0PQhvaCW6PtVSC%+)E^OX&B3!QZY&1pxArVqdxhXw zKX-Mu#f8-eFLZPrS?-w;yL4@<3>Yjpz)jb6at$R8j zR`*Ikf8EDaT0C{DRP{9mPKMTet>K{q6(2tkK3MN6MP!$%z1l#G{#sXo<9emi)jo>z ztj>d%D^(sWVoK>rU@NLarT;=|N_9l` z2lcn7Iv)CiD~+nwx<4>$*$NRW&0C=YgKg|Dt)nY8jt3jMVYM|wgNL?u!aH3bX!80a z#29RMwWnho4i=jlzupL``UTb*;aY{EzjZ@%%PdApQUMvMdV?yd=Laj>KbfQorsFhr z`YY8xqf{!A&eAx~3h%#EDKMR-YzGU;B4>;4SPGj@I6^%U*69pDx6g1zih! zW|mtj8%(29SY@kj-E??lYw!FayY8{7q;4pf#tE) z4W0Im^6YZk=y{XV10_9n>*kl|$2u(g=w4DEXKBJtr?Kf%AJ5M8C>k z(b?BFt0DWGQ(jz`9kh?Ce8dx{63|(RxL{W0w6_w!x22;J-aD)Exv+h7mT+Nvq-?6} z=2o`9Q?E8f`EC7M+G+Js2^jL&jE&TRWklL+Nt>#f)!3mYQ&#Igi|Fm$?eSzC72n`i z78`4)4jA6OmA&+_*@gZmdSiB0xw2Lu^;fH>9N!alwk&GxSXgdO;Uj+WQtirBQiPae zD&Hmdu8~gPHiWWBp|YsbYinka;*Gm2M$zDiUT5Us=(q9d$_gWG-4r(R@Ty6xth)FU zkFs>UWjc<<)vA51QRLuFGj8a4jEq=^Hx22Dmb5TTZ~i-^w}AK=`IWnEN$m8-j{Q6A zBy3bkoBKfaQa_kYHXRK7m!Qgx9E-KIjOl-EucmyrkNjcZKJ3K9CO=)eX7|tDw#DDB zJo?qYcOHG;v^%!l=u`79j)aBrpFa7i{ifW!<}uID|DO*W__04OdgPMA@^u=&yXVe- z{7YOf{^t49e_SqfUi+PY?fL4*zq$Oz53TaoMPFO*$jhJJV)k=!z2?PzK0EpHlb^a_ zm7i_>-1gHx^!j?&oc7PN+kdkB+OIXQ71wL8zU--gy!4w*HeUSWZyhvojYqb8bFV8N zdg~7_Uw+*cPy8*e*Y!Pn$Hl!r|IN*x_|t{AjD4zM=C9_jI)CkB?i_vMe?5MDT(3X* zuGbFOkO=&iKbE3rlOh`N~HZ z-Sw~9?;Je;(d)XNdVX1o^UX=Oo_X2XTmPc_w1*%4^0(Jt{OLPx8ui2bPyG0imtWla z-T&z-Gj{sS%bxk>78f6}=eifa@#NJ{fAI9<7kvE5eGmFpiqmt?pHFKadqnedr~KEr zYo7YXO?zxU>bx^wnQ-Oob)VkhwF$Q#p5pxR)6YNo(CEYN`B(AM<(IAgfzjK%^64kv zIHYaQ-yA;ur#scX{$z?X{g%sX*ZN}L-yi$zw-4X;&pSW!&nM1X?cv!UUO#vHmKQzv zzEiJDaps)=oww@udvp56zxnCezrNz$4WE8y*Iyw9mewR}}{PK?1Z*=`N zH%wmR<)7Wvv*1^s+C9Z7eg4~<95!|A2VU*F{@4?4`&{pq_ka7li#|5?n#Ff7Z$5h7 zt$#>yUMU=L;;B!(aoX?y{)ZE4#(m`EqZXWg(pRt9cmF%i+Uc#2ojmpvDb8y1-v8k* zops|8M_+x)ep}so&UQav{^t+;;E2Xe|I@R>u^a#Oq#tK-E;{ed`wBZ;U!MEQ9|lzT?0zKYGhP&tJIt&(6Bz zk-aZ}Zr5-9{@O!RoOO0Dtu=d>mZ!F>z4?>RywTe?@fX`nzI4M6&Z*nu^f$ZqfAjhj zXZvT*{Os6gFFO5O`|SJVhCBX!^2I;gFd6F)a31! z?6~yFI}W*E)rS3_EMBzdL+7VBYi|GSe!rYpuG{X_zO8?A$lZUv>xDC)_)hbu8)hAL z^Zh@)_2|s7@$yv{tbM~L_c;Ebea`;(FF#%W;kC22eCf}pO_*QY^MY4Cw(ruE&+2Ra z{9||A@x?X&wDIEKEO_CC2j6=CuWmW))tNgis-1qrM*IHhkot)8+soJA^tP{Ua@z-= z`u4_OzH8IFCXQL}fpt!LY0Mv=dA4iJPj}ue#d)cHmwmo)`Kl8EPO&_@UiPqi!{qTduALPHc z=KZ(+@Jm~+FgXmr`Dd3q%RQ}q<+hd)rhz@HN%JGm8?7@s$}R0}{gXx(>DfsK4f(vN z^`R#w_n)U+_WxFPmK!<8nO$w={@f-tyz+8s-y8mU$%CE6`V%*JcAXz~{O3=*zH!^_ z7u~Ygk>#tOdFu~_Tx;+Alu`b7`3ci=x#@+aOLNnUOZ)%kmrk!aE`H)Omp^WL&C=tJ zi|e&&KSX-rjNq|~6mY(v=a{HokPp&ovkF6Be(mSVh%15W> z3Ms5{Fl=%qWJs)!PM%T;YpTZTY40x2Z<{=IQYE-lN0SMKSJ!5ZD^ zR?mVX-?l7nEIiV+T!ysT(1G2Ori9!YDf;Te!snNJds}ChE90m#pyx!5v-@Cla+=lM zGQX=Ww`NM31A?W3ojb>3A64Tg62hhF{5dvk-q z3sUg1zufrzoe!NnB#)kI>|4I~j{^rI_eSVzmp}aAl@~vB*N{B=vOJbO{KHFrz0+Xi zg_Y1{uYPT4=;BJ~b^rR^vzHDjZ%HNi+pj)4H1bg?^p;mHJ^S3Dp+{$N?>zHg!{Q!O zyVHx`{Qb#4|Le6w<1Wi*k-z%$zdbxO_=HOEvd6DE@6qoKsmAh3_yafI^!;W#_+s=%(jScp=xcQRCZwDh;i~ z@9)E9%Z7MF4#zKBHZ+G)u4(JWoAdeN(&pTRd|_Jp*PJUA7wj@NmySM^%Z<%N*XQP~ z+8E*axfAlmY0dd8LcTd4mnRhBG(UG@aYDYiu*=xOm|SCHgdEc!vu5tZ{APvR#6oFl zZ*!sa)|+n}Id?&6+3_bVUz`eQj8Y;rzaWaqXT_xaKa|T4%Xe&UOd+x@mX^+)P>j!r z*w_=5PE{P6E9F*gEXCi=3a7+*scF%~s83;PoK-@XPn#Gi=9X5STk2jgF*miaJhie= zYU*pw?UjmFy7x^_6)@=^AT;tSye(C$8z4InU z_|(FfxEKawLVK{O%ciB!RB|b|V|<=6t#QkIA$q$MjaV;rc`@44^pT0VvH4PNLS(dA zVOeQn^kj7BYPnq2ow>%k$fRj<w zU%4wcp%{Si86}sZb(PDfmnPPfngcgZmq*K+CS}o=PNdMO4&O{vfq?xp4Vxy`9^k-BDXYILqKtJKuy+QvOn4Wl-J8EuP# zi_@~vJ+USm#S?3Hiw38GJRw}tM;a7MV;EJ3UQKiDylm(-z8*7mHt)ljd%li!vtU#^f7Ig(xYgOZmRi zML&o^T4<_SH*TO9uM<;4PX9%&b7H>q)?38|rKjU?c*H2M5N(d+Pv<)3r9A$VA`WB} z*F&Nh4U2p_<_*oLIIP5oSeG&?zH>$ma~mHoR+^qKo%V}#=LBZH^v8jtQK^B^no0vB z%lzC-C0K_vE~|5dR~i)!ie_c~k}v(azLG<6NDf)sx>wAhSjqWqjmR|Kr4cnLU8a$h znKj^!otGtl>zb$1&755y(oI<>X9nT_PW@9V zM*cCiB(yu1@6b7{fD9_@k>SlR)x<;*Nn);vbP-|YeY*0z5_Nwv-58q{8Y;Iy zTqu+p_lU5VcC%@?rfJIw`P7Q3g_`(?+qoypB;COc6_Y}6#GR5MM%*+fr8^@ytM^D@ zZYh^VShX=#{+@ikW?1D1svdQ!-sYwJqUPFY#>BeyCe}6=QjOwcUK|(Wpt#3+6N^LY zUY~B?sC%(e_n5h}x;I4K0=!>jNxisk-%|_nM1Y zGvea#X1tdApfIh}*_@x3)iA3!W9~|me8Yr_QJSe58cSUhMnx_2r9Zv()?4Ww zDm6|Rl}hTHIJ!CdD0(qIMn~g@cfy2Gjm@K?Erm#2lX5OJH#FCzT17xzB_QUH`sTW7 zSQyQVXKBs6iS+|lW8R2FbDL`;Vl`U6G5LQ=1z=fU=kZu6)Qx- ztP3k0cwe>UUGLiR`fPNhme;42H$+{BwY;Iy@==2=ANBT@H#A1|hPAwYpyjERsg2QT zi6q(Uagr> zliC&$7EP!rjgIF{{Hcw?V)Ulpz1E8vJiCixv5`h%N?DsaD+W=BXJyouMyF*j1dywsO+l`#{ee{QtAu97OvT+!3n$|DW2p|xw6P@l4i-!$0LMqy|){$87NB(|uMKhS{AP=`z}67sm~WIWAX*Np*yzT2=;0_6UjTA>B@m z71^Iu#z~~jsvI?3FfkjyVVJ9e#{HQXc#VbO$QvaHlPv?_O2Hm76_=}+DeYmhV{ zC%M|jIwCzfaf{n+1&*$kGYNg7!#)08rJPem+uqsAn(xA#W?HHvr z{vw;Q@=YHelJUg8pi! zRt)rIEJvfFwb?)%xD6vLZo@P}2=l=W} zCe#g#sT4cqSDiuY(&U^CvUoN$71xc{$ABxuy%MucVXt^hq_MQmdg+Ou;->2_m0KmdxvG;;Vv6=vR@kYbRjaoN)Fy%G+$bo1)ASstDRKsqPc@hu^KrB^ z-Qj8Bou1OwnzUFFlrv zksnXM$h0ZD2l|gv!*fl0ubW-SR%z)^ZeG*42zfFWg*0B$P<^wB^+k4DMz56W_l%LB zE4}!`cn9vkSEJWr-IwOXs7c%}**Y=ZaA`G|t>q)MAv&y7965EdlvWx2sbh;ETLtDz zW8PEhruUS3_4kx|?e~=WeeWrC^Lt9Y(R)h0*?UU;!S|GU(tAq1)q6_4&3j6{{d-D% zXKr}%{5#!bX|>gVlf~O&^(MPJlIIK4(w&>#qwkPBpKV19CeI$IjsMCQ^Ggfy6%Noyw=hY&`MfTDD5aqUU2(8?(<R;<&%~c!7z>No->Fl@`x!8XI+Nn7er~QZ^UUM@?EV)I{F# zk;+T!$4O~^e7CkY{eP_OtN&ka`(^q5hiGN&+#0@XElL}=rQ>6ptXNtz24U96#Zqqf z=(KnfjkWHgc*qyxVI2>Q=G@M?+_Iz3*rqThE$ZSyxOC6-8eEDk?qiyZ3l~(jLWaak zZ+3-JZr{i)?Sn7QBBaBA$5T44L=kV*FUZzLh1;`rUgM*ywhhT{$Q z#DI*!m>ygCMN!$bUs#j2#$x#q55eZ#9usRKpQvPPG54k&vzmC-iqX?th|5{IQI}ll zn6#@A|4I+$J15r0-;RlO^CnaZdGSa8?+YnK;(4XQ!fas>dwP8-AnmKfo9Bc=Y4!9> z&FWuFZAlj@#6Y`Ztcg8z=EX`8XILM+ViqR1{ z~KQ71Xgdik&8HSFv7?=oHQ6= zzMi{w>?+r#6IfvT^BaB>!I|n0-T*MCtBaEEGj|L-*oWlcy5n`6l=KffFrS(;| zx6qNjW0umBEFz|7>7-pJ7S@}PcB&%7?8z3J7V#dM_SKsUjrY~Zb2XNH&GBZuQ7%2_ zvuAy_*uR%Y32bZkJx(=u%W#DjkA>Kk?}&9*K!#ol{-GY}7-?6I2VQCr#3 ztc^8X`g*o5dzFp_+SJ18X`PpC0yf1_d@rzex~DW%N!MB6G?({}{1 zZIaf$`Ph}N?0v*ze(mPi&YU|jHmg6BYnm7t$Bs`t<HCB@E(T3=Z6u2#vMu6#bKT%ueqg4G zN95E6Syd*~MUAUFV5uJ2-bSi#wQjKynYMId7rs>4T8-95SaU;cv1UzN$`uk>MJjz$y~m5LorrAl8m#8RQ5Z$e!x{qu<}s@Pon$+59+i7lNdFRjP(b3>)4 zbVEFP5>K&oXWHwC<^3bs@;-}N7#5{|g(#Kg*2e-VimQq87xa|Y?klamu;~+#I*ssD zXfBQmahwVnRoZ{<#QM^zu@r2sU!^IZ8}^gWMrvL2sKHvjW08wWt1d{T_6-yn1;$3& zK!L?-tD?X{rNF{S1;!|>>q|RX0aF|-cSVg#Q`5F_e+$zWmoXj05R7-I>>XwEVpIS3 zbXoL)@8VLAHD~)qS$Na-u^h~mZn!VrqS6h0Q~xe)DYl><+dH~Dbwj#$@7p`#MPEO> zcj=Yrln=+QY22^*bfZRv<9ns_`j%d|(yf|LU!cUWiTDphy42~h?Uk}f8*>lu9U~`Q z&2G~O{rP>dKyJ=u--H!X_RYDtN7D@vUwfy`u2Q@>rvK^Gw9UG45cm6Id&h=<>At9T zG+>=vVOpwh3;}3ymx$sFuXZ`8QPpDs?B+N@6vhq{2w&u$-(BNEK+lx9@d-) z{q3;kMD}lMPS^}<&R??TJTbgEk<&nPo_>3CUK`q+=c>(lY46g%BbWbm@4PtJoRmds z&P&6Z6QR!!YffbUw&oO9XwGX{bDkUCoXBaQIWN7vIXCY!WUyViPvjVb=Z1YsxBUG7 zpgGq>y6Rv{S)}INu+PxJ7NJ-DeCS|{?BCX$^u@x^!FKaLX|P=x6&W(vBBz1o+^|m? zY^SArC!U09(>0eKg=tK_SZP*_^_PC0E;YrMVU-)|>1rFFOP_IJ%d`uV0#mL3l6^*S z?9@KDPnyQFv}yFm;Et==mH3SR@G`8fFYXiff4UmG68}$o=K@|=aoziU_C7jCPwUwD zA#4NtoEQ*bgCxt6tdQ8p%`FgKPJmu|`>=&2EXlHDOR{WIh)pnwo6rVQXdvWa0>s4N zhFg-aNkfStFOsGWNr2KOxAk{#n!0V;khWh-Q(Ertzh?G%$THZtaP#%Xu(fAq&vVUs z&6+iHPQ?hUUbIqeA%)Zua8x&YO!RlkY`W^?q02n%iwD_!mmk#AmywtEbM_{geteIx zv2befvQx~QjmLx9mr=XgKv6+5SXr2URqqa6)=<%_r!TAM)pM7*UVRYXM!c!bF8@4` zlpQH5#$H#5BxhRUXw6Qk3{f0lmMLJ7LCBb4#+VVpYmLkTANt{^|Gu4CGuq+7@(^Nl zVzSp2fJmF!+||85F#{6pv`dNfT{fNEda#E4>0I`0CWyXn*$_H{j}vx5k+out!i<<6 z7BWe=1;OIO@&srTK$J^0o816a1M@*TuHBTo6!ENd)FH;ATv}Tb&n5A!j88pI787c7 zBey)QfO(KkE7BFNcMag2Aq~f+7HeU={d@o==q0weJ{kU~r?wJC9+0l()?7;gC96~8 zSI*p(u=Z%pI{|Czdj8z-3ybIj#xG$Ajh1FX@T1^Tn}w(~T#N$AE0%2p<)$ml@p7{z z>RvAfuRRuRt+X(J#nLDug1)~R7Qv;%xob#o4cF(%>q;UlfV$fz<_jGrq1-O&DkvG( zm?u@VnvoB(&u6M7VKvI&Ob-pIgDJ4R6}8bKbCC^WvDHt5tn;9z-I=H^v2TjRL$-<7 zHFDxlJz!U{xY#T(HD*+#*&57A-=RH8bjoj_G)6~ZHmLGEny z?VZkq`-t#Q;HfFzn7&ARoHe=gY!}|#J)}CC6C=BaODKx#N1Q@2tjV3d&>^iMXD;?Q zni1gJ&>LHZ9inDH;3U-QLO`gdXg(uB@vc8LDq*AEAr~*(WhBRr;o@oNP;}U53aAt( zlMKj~uLpbw!Mt=a1}E19`3B6gLU?v2Lb@rlY$Jg3xrXyiHhfe_sS}N|1~IO57i4bD^&>gMc2f=Y_#4Q z?3<4mBvq)%vO(C$GT&$vlxG%cM5O7OY={}~Sy8N%dX*;9>LP~Ju(1-E*V7pT1n&~% z!=5|AK0F>`y~N$99{7lHFE-eK#fw=`h~t1ZA}uV|A}wHIj8Nzu6QdGHgwB^ptIpc< zz>Yvx=!$Whn?)8UP9s*E9#@5EtVZ-<>;p!eX}B|tLfEre`D3`VJTgTD()HnUZW{jG zm}R&+mo?VlIOv1V849Hs6HQ=Nr1u5;!^W(bVMfd_1yf~SN>EBMOw&|7h*EqitxcdQ zOU_YDGpjko11$<%i+}D~jEZY9A<=ufO6_iW16zidP|kRzzSQ!?_MOEc8BOOJG89{L z=UA->8e@Y2Y_LXbu%^TYK_KymZ{zx(@CP8H4P}XK8%ZHLKUiQ<+fQI;Bi?g<0RMoS zwi1#PR(eevp_GMs2&s5v`A$-3AH1M;syCQVgcUKNc@}CRG?!4C47~w$H z{1Xz8CR?t+qn(v^tLb-}48W26rQoLBB((U1L#u8gR_kKVpLWx3eXQN1+%GiiQ;Whc zX01>w;s1z~%684}-H!5TCifaQ)52&X1KMm036OIvB=F^!Hb}*9SEn`=Pjig)(Pu$J zw_Obr1>DA&Vkkx1)v+M~Y0PLGG<+yZ)!3$itIYgHfZnEJ%Vwqn=8-8r_{{!iM1{ru z3goj1jk1QeZ0X|D`=2>mi_DDp&14~~^*VkHS#c~lI80D{JzH!UVb#PIlUYFUb}%so z(lU1=g<37|5Kj;$*dB+5_u9=jDoc%92y2OQ@~6@i6Kk@ z0TRsC?+7UADZIq9!r~Uzsn&o};8G#U*0kcPB*rg?VK}wVnoL=fc?e$hrsatf zsGi37e#bYD{0=Cdmjjo86-r(n7U_znx}!s~mL1|NbEQFAbGd#JpR&Y?QcuCE^k4DQ zwBZ+P07U=6*sGS(av%|-pvkAz7HEe?_mqN6*>mP3%vW1VE7cmq<`wz%bfh+z3$3R~ z^NM>|e6ng72kB7p(c|gNm&%HQ0#AF}0@us3)y z&LzWzIc}Vq>t(^gs&URa)^Q$LxIE4$rJ_}gv+;z+iK13L&JRDOi95r~CIxLHArwknLZ?V;wpkGTo|K6bG#`LSE!Gtt zL^2Bx`77KtCnq2d^zZo2SO2_bgf?10p$Q)?KK+f4{vf%B(2qSa)&f%^3*%B?e{A?viqvo|GKbtZZV7$H197{cpo8!4#Y@Ut>jtkadE9rKRgpwR zbwxC)9fsmzTWwc;liP}8qzp#FBs?3okw+J54L=Pk4?mKhZ=f+3%Xx9lBe%!%f2Ek3 zuq6{*k^x2+F*^pIVsOFuc)r;R%#Y{Yk-NMw@8^PG*X6$w>m3B^ZQkd7(g2C5o~;uf zH4J1neW&-xai$%x*w~r{bAia=MRRU#*{_)XF;&f%^4ZuFiuJX&o{O8M!#C5b{M=+x zKOH{e26ikxvO;rJho+x5)5;1Fn`umN=kUf&lMWAN(;w!3wnlGVuW@ac`eUSG{dDjt zG}~z6oI@nW2>z(IV3Z-2!zOirZxuLIXckt%ieg6F8a|9|g@9xjY`r%P+=+M`l%-7E^^DIr7`ctItwy%#+@ps#bP z$-1>f)=Q5d>p3N|2H8c`8%4v&oB#==6L*fHQ9mLd(>JrZfvGaq#rRT!x0a8;C}I>O zK>`a_A=Mh>c z9qoydssAC;K`?(l6oL>uD|#Vxdl0y6$V?WJ>}XkCMM?6L<_Nk4*i!s<(?hMMTM4%C zkp&snABMK@`=Kc)@C*SfH>7HBjS6N; zGUTMVH!0017?Bj$qn<=qr3z6jO~lSXG7Hp(X_$IZFD#TWh!TGc#VNfs)i~@ z@nE_axt5eDRoaHAF9><}f_&NqK1mW!>RP z8PZg(6rytSb4jv|xMZZGYD1VRD;=fTR5F2Nr$B<@B*-XU5lJrzidTE@Mgq{UZzL$L zR}tk<*D)?>t>8c`Tb`lr58bdC%C1H&*1r^`8d%tg3E2t}OT?yP>*hEG@(QE*#G%7) z+_l`0S^P=1g4Pl3Y@ytnx`oj|j?Ar_Sp~L^u=(u7q_59Rekm-x`8woA1dOrcYX9%* zVUAv5ua@DQaDzWEXXc^?$ii_ldWt7ny(1f2ku_=-Fe}jy6WWS25@E4cUn(=mnH1Ji ze(@G!oFl%2W_^wnz;g9q0ux1+TCmDxAfitWg4$wdTsltx^aO*HUJQoST~53ISw3(K zh^Y~K(E2Xx)_3Cf0-+h%BL_`4v1W7C2xM;uwKQ#lgBfoWC{L{VN^{B)(lo%fMW8z& zB#dbIv$~Ko2=8R+caTE^W``2Ted-d7dbS^^Mfw!ZYP__iAA5!Vuf7dARpfxEl|!e8 zRoWfxAcM9MwK*xh5@_&BSm=Ac;|Vf!MJg(@s&E(BBsT@H21f&}*)hi($JBQC!{~>R zt>i!ph;oX^2ZeYxtA?^YemsREEo?3)`h)EEmWt@vhTnrt)|rJ_3HChJVo@WUwxm7 z!$r9@FWb`Iik5o(0M*Rjy<#7G%A^&QddaQp}(?5N4{aahvzblWie`q@f zL!ol<`;HfDd~85r7V$ObT+JyP`CM0XYEkZVF+%{8^K44Rz*(2Lww!o%DY2)VxVn_M z7Zh=8516sG?OX-x%c+B<#9J%!-dWDOt0H+%IeAODiXB#ks~PO8$p2Yz(P1W5AE{!7 zyo{V=vQ3ey9_dzx0+WgT#UzAeIY)Gq9rKZGZ(imopoN_=**@P$G;6lcUJJ?gxza*1 z-t{Q6Ks_7gO%{?3^n60L?#s#s zN*AhapxG)LXtvr0O0;AHC1c43s)0BgD3v-JsPR0;09vOLrtuTUGz=VPB+xF;!e=!% z6gilZgxX(YXG9ZWB(QSX3;)u1T@VZ>08)okL z1P&v7Np3QLh0Dmo?4bleMfxO;pLU{fNI0&g1)|T^m1eReBDI{?7Bljxe!FqO32n(7 zos`vVP#94`QDunZy@qZyKA6lf2^6h(9eN(S}%Sv3kMaf+Cz=q-3^% zqzI=M<=&GjuF@h#(mfx*jA6<}YKqPEwKoWqlP@MD(ZF=Ul$3!(2yE%IDo4OC>|DAz z$0)t6I=wZ?-&&oHA;r}bSEsY1?$S%U?yi3GPf-0O2L+dIO19E%Gh4PPQ>hN(<8(-R zoBDiEuQRlnrqNBI zn@*cov}q>xEKTg*jCA-Pq$AlU+_}RLnm3MsF6XRGg$R-dL%f}-_yg=s(&t=Glsz*p zg~i|f!8cBJ%6BLS0$K0VY&_J+G$@;eJ04ksu|`V**;8~#4l_U=mjh=6(6vl?t{Cz$ zxw%P|N8L3q3fXzkq_eUJNu4f8qhv!ha*GAHo7paMXrNqVz%c>x#C6g|YiTRasGPQ@ zWd_5zg^@CET5-D2Xo_sXTf-VR<(t%B(4FC77M8UsjTwuuS;Hb3FQ`lx2he)S8df7~ zm>&xVMTQG?u4fuV$r`4Mjrb(b22k+y5Pay1jjL!L4nWf;-T6eY z_RxwiBOE)B&x!#_0BKd8-6Qwaw$U96IbQQ5Q(pi z8#?#{T7ueqlV^*|BIrlC?QVWxrNUoM&v2&6HVK`ZjJZtc>@YQ!?yoS1AiG1w`GQe| z;kZ)i+jRoS}}~Z)hljix%X# zE4!7q(WyN0470PKG@}wz(OIh8Z>BsFfEP0FWVL@upW^H$2W-CuPJ-L^VO1{JX;`2( zTP=EtIjDMJBxZoz`^!N6R20f<4h75m%sJ;BW%I_L{|whTOd6Pe#XsZMM05a-DPeFk|_A8i}@YUSpp&gO9utURw{nS8$!fcz0Uy0gU7^leM|{MGJ-C z3{>#pYB$Feye1_WiOUv3xj8CodO{)cZjR`F-px@V=jN!8b902Lc{fKw`;doju5dE* zbES}*D+-Z8bEP!r=9uJzq4|8!opVX2g?FpzY7<{nW#WsfO?*U4CO$HjOne%EGx4e0 zyPcb(HIrkQuVphWj3)GMjtV(9M}^GI5ju%;XXvkHXJ7T~{LBgU|1l-O(!*Td_He(f zO(*!Go2bvFl3Ozh6$c5z)wx0;En_EgJF0~XJ2_zfB;jgmOBc<3k%KAcIkgYZ-^BBu z*%seT=iYz{Y85!i45ODHe@Z?O-bWwC=1++zAN*MoJhb|EY%SKJVwCgBO6*RQI63$h zJLaTryY6BkJByRdz9ESYsV$)#2vmV2N0wV4&jj;w5&E#q zIchoI(EMoytm9Iq*g8#c*$f!9!?`K>xX?%2u#h%F<*Xsx_K97{^HM5ur^sScYr-{7 zX-r3=A!IsbF~Ec4U(|^apNZK(uazp~x@@YWl%aE!8Sjnj^bjQ2o?>d_bFv zXsIZnO4nnj;Ie#>SDYo;W;0eN&S_M6t^+Cijt{hLJ(w=4leNB_W(YM@%PD+FQ~rdK z)1&csM^`jw_nnvES7w*%xXXLhTacBzrMc5bOH@=REm1KFn2$RfBp|NTb@RN5-1-!r zCLeWR$70P~Bgmn?L~aF=^g&0YG=2IL6xiYCp1*X+{1sE2=F`3tbFQHaim+C5FW36Z zMnVQ@o+U4G-4?2~+V6%TzndV9bC;^rY%U2zS0_qnS2{#os~3dU6|w^@%)O8<8v`!S z9=Lm@qc2XpGai3nj{wD}M|cm0t2A4o+Q#N@j}V_X+d8&5*5)I-)A9YQ6w4Fe$zpA!c!=8ezD2q%j?hhGII$6UUZ9px4K%CEz*YNRhat9Hnk9mV@99^2*fNBiic3^{^F39OF z{K}9`Yg%`Ka4}cG$i?zOu2Lr2b6P=5b*2)|qV)?nf)U(~l?y9)UM(1p1gbjL{kkOj z6zVkv^&UB1RmnKO0#QSJCFd|$s*Y&D*UociW5i|s=|=7tv6GYNIP_H{E+-pa^048o z4D=&7neoHuM}#3mcJ2lk1wB$fh;3Q}GPZ_s0WU6u9c(Ojs+TIH+5W9+C_*J(hfEG*OE(_;G?C7?0c`BY>_{OUAKi8V>$3UG3X9~GMrHQ8{a5Y=yRNQh=) z0X~r`awU@xMU)~$Ya~QoWJ2oIK!YZvA)lc<*SilF^cxw7uLf5`qzQ4~ zyxFkOx$dPdF zE~hg#daNq0A7K&3E)#?qm&~jqOMx>Hq4}sYVQwc0*mWr7YIJrhl!1?BqIx*4-A>?U z)VL3FlS5H4FKksZQYET^&R-UoZmkSt64eVLN~NWLV3@^_%i$D5K6g=`m(k z&bTRs3;`dgC*~*@%|Q*5&z9;3{5&0!>Gg9ksGohfk^8O>@e%xNaV zr&*L!)J({cY~#Wgr3hGqs@Cu0#Xsa7DTR4bd}z-<2vArm(_1kE_!CsIj^)O41wg7>Mv&Ivilrz{VoW@iMDsICU% zeeN6O#h%z5Fzy)&yN&nB9j1!+aVMhq$qHhur zIudF4!<6ZSZu}B>j{Ky38>@#prZ1E5jk48SqPr;{9Tf!_FfkWu4E%ANQzlin{JaB4jVsC+;XayUGUVM`&4Iv@ByhmOd zTRJlcme{Aks!v9cLZCE<%e^>XTb1K#U)TgQQzOi?ZaAq6KYvRib)AlFraLidk3VZ( z&63r`1Wa@~&WIn{k~N%h$qKU*va%`C#=&N-TJ02v;nb$weJOng;pJM#Qq+lCE%n;q zMWCZm@QDCWBqvB#Lcat+X2_cxOiJ3e0@_YVO0w8WI>2=1?!{$Qgv*~ai^gigRie0q z=pOEAn8_Otub=y^FLa|rLDll*wOBs-l^y&s?PV)l!t8w!w<8juawi)%J{4Oz6^TYWM6Or>S=IJS$~kFPX~kchd5 zW1`P+Dg5!3o_;a=@s(z6a{_HoznJ~_+D5@Rfwre#%zk`rx1Lbj(=TQ}zP8&=sO{+& zvmamEJtx%m^o!Y#ukC}JPp_PCIa62L@?>p=$d2)1_L+){!mEp$GSYB+>ZfF@0V9De zz|ClKOS(o@AerLqG8x_VRbdP&anl)XC3fr@mYi4xYGf5a5XmZl++<0J!+laf}uo38U&g4$@^+i;pvs}*V#zwi66<)TMKoZz-E*3@kdQ^XxiTns7ssjG9 zThz0qh-%zm*A`{8U5HbRJniX9hHw6=Cz6~iYjSN-U0g49hO3iYS(XXb{W|)duhY2H ztaJ{vLl!AgDXdk0ZIN%D6%Uqxu;R`l+l{3Us7$sDr3J0&TzlZ1z+>7{TgClE9%y_e zwd@O~O1O*+04n4zBeQchRKV#k>1f=|tmOhhZT_$4g$)vYQ8q{vNH5g5ifn|)^Crih zjLcK&rwbFRP(WZXzX;8}bC;3Y%G}ph&b>~I0RP&GxyP~KmFJ!x`O(~SYm+OR%)KtZ z&2tLL=01B&bFcQw_f@&MH`|=eJuPVNU3(`!_l~%7qotYr(Sp=@vK;M-HWe~5tfOY> z@;zRsX&L;|DtMO^RQGbZtfaX+6$@SHUIE~&;Or$_x=06`(4_azxu|$r=ET4Zy)(Q@#ndW zN4+@ATg#$DxCEP#K-iLDsJayKkUs9kRTu+v9eW;2J)l!lI0+$fE$KobgT0YSm^1>qGKpWX<8dyuexlTl zcs0}TfbXju-i*-F-IA{kS~FE==9r^acQn9jQUqD^-%IC_Ir+MyK)B(AAnYCKun}Up zIx2)g@e)X;q0iAqfIUa(m-}__P?-0;Fi*}kw~8)E_@`8%!4huw2`{7y^_Fm_Pk1p^ zXtab6`-EK~HZ0Y#*C*@_3$rZYKA*5BWRtLEs?gjUaP5e-a|`F*Ezd(rK-f_JfPyT| z2!2w*Sp*BY-r#;kniQGc8{DHvqat&9gO4auugFQg!Ci`Q!QfP3Zf|ghB3VTsv)dHG zszAlRqaaHmg8LPmB~~!6H~54iO^VF#4L+_&qaq7>gO4gwuSiR8@F7Jwrae_Sxi|Q2 zMYsxas<5y(_<$l&Z}2I-!`|RQy=V0X`}A(?4L+tfG;z1y4ZXn!_0IMNzomCmZ*VVf zNkdc(XDf8E#8ByCi4tRsW{2Z9TigYHE(3QPQO`11Uw#qTx|rt_o>O^F93TThB6TQI%W9f(& z5*jD8Jgy_Ol~AYpbZa=F$=E`CS=_*v?S#&aPbM@)=)8C?p>2e?m~vTgdq`}O*jaHs zpI4jcv_qzc(Z~_RP|m} zy-U$p(fbtLttb%@+%nLbBu9J8g7;d|ekCcW@9(pu2bH9t@ab0n=@$F+kUlA>+`nN- z2b83sl77>Yen&|PD(U@}^eH7NSS9NQiC4+||S@W!zfgh`0-xdM}+;6O`+3 zA^|K^Dce?;MO&3vQ%0oPg-)nlD7M;Aj3v^z6lx}Mb`+-T8?55D$J!<>n#1x8eAZXH zsKjDdCmfbhIPN-q1nlc1Y;~>Ys={@c>Xn|S3Z02wjqkMhr7)K0FM9?nq$IlDvsXhT z;{BexI!tN}2R(B&#N_)3I|ZuEu%a1`=dnTD(<7UBr$n~pG8VGt5IiG4aE z6z_Dz+YE>E=p=6Gu~od%(}6gpCm-=iM|O1<60wS1IuaMJbgThMAY>GSG(?918g;=S zMZK^I5j<>CJOVB$#sU+CTD8f?-YblftrTN=F=ttEwke*rEzWL*eLC~9IfqA@Ulv5m zAmjXEy}8k(S?~9x@~7y%FU-%<``xMhsd|4xmr3!yIh8+6@B71iPVe2Re606PseE4V zdqXafy9wb4_hn?CiBK>C-Uuz{Z=TVUKWh!JM{WM zm|v*(*8Fn4ZVRPKFAKKhJMG#Vl;lVz$OqD?7E}0fQA*j}!yzm|LLtSmj+j-TZThB% zTLX4h`N;wa;z@SxUd(Rg>Ig8R$n~N60fm;Sar<#h{r(n{hQ$#ZrK39SwYeP?+s0GP z)OAn`FbXb_tzFx(JqoZiZraWwxqfOw7J}{i)h?>im#8>vJCTSlQSoHH*eVtKa?+Oj zeJu7$*jV|V?XeeXv@cfV$ADBpmc>fIy<`@tV_LXI(nT7WSJ{N^OA|O1=odFtrWphZ zich=9Y$iBp4c8V<%IlJ~Twz{3r!ap!o?8gF#`EI&fFvxQx}85KZJ*$8y}F++?sdfh zsSRW}t}iTzXEC0g6Iv`e8~#07w6giu|q+k*!Qu~sD1PpB!LMQA;tns^?eUnbNX&nI*> zAucy0bS0sa;<<#@vhv#%3RC_j6^8iw^92a3E?~q6i@Us9pE^*8xK?*f&zge)1$wm6 z`#&TLM8FU|SMm6D-^@!D#|8hM=?JR|4h^v|kC>)4Y2iVzqbTgN}$o5aVT%S@b zk`GYy{9qMH+$D9PUbugsAH3N@IYMu;Pz#~+E#$7QP(Ha~_gb2}xUy4Ru|RbGBMs8G>0}SyHGYb;u2eS zA%(uU$C$SggVSb)3`Da2Wt@q~c6Vy52Re!sM5|RN4mR&g>9`bCQ%KuC*~Uc^8)*lPw4i~pYWTKuL!B854#4AHKNPTW z@I%xN{NhU-Xg+dKhE6jKsywD=Q&GuiTQQ|Lk{Fh;Ro=savKkF7$fuZ3PpCDTPb^t> z=m|i>dPAWh4BRkMh}BleQ1oTXKqt<(LCyg>;>0c%dq-d-HD%-=aQIncwKzw)X$knj zpMsi$&GkSR?t-xLEb&{=I_BhlL)kkH&pcyxj_dWDG=r$8TO3aUN4G|>(`eNpl6Zml z-E$b}2^CT&l)Kdk)sB8q8>~?zm-d&~d6fN&BPrIhF}*7|%8+JqUJnB0E?dS6?w|_P zfF<-nWLWe+8$F#2$yX*r%Gk~aqn(^8$km^#uhND(1-^G#o8`iUVpXgcb!< z2882PEN~5{=*;cDKS4~ zR2&pr^@gj*O@P>efC@4*B6B46IwGR$H0qDB4=+OE?253>M*H&eYgRISu!bW!wwGVC zjxN6vipQs@4JG9Wvd48^WdBcPvdVU==1fvtktt zR|?S)tfC)x=n_Jx`g~YSR9;-$)5(C@(LQp(Z1id8YMQimjvHVNI$hoxeO(%PF!eeN z1q{zuZ+{*ID(C_gQz3IXY5}Ej#CTt7VFP5r{|f`a>xs=IHop%8MdFOp@F{PKua+QF^>QQHCN%^*@koneP7Jx|Ys;IJHpSX$=#GC1f*AqQ*R@ za>zXW8ldqy^H|bnC&ns$e8GA#n-G?QqG(DwO@emv>tK%! z0VroA^knu}odY4 z=eQe{F^D1es)@czl${!*n`` zrVA|FZB$G_JdcH{Xj45JYIA&(nJzZny`4oe`;krQmLKR zx6nJN`@VUkEe}8Wp7bq=Cw)ueO9hUlP?e(tSND=`PTYiRXkrO-VDxb~ZD-H0^;HOU zZHtD+ca5mSSz*8m&P{xXDyCJ6guL7{N_wE=W;Ko=J`tzWln&<>>3wXfaHMp2q(?Y% zBq=%RYm?7%)8mNg8r5iGN!6HQN!7?=NhN%ddl(YMacpD!OJA$u($HCzO6*KvlgVi& zT`kg-$_LkLMQz+(<&~S41sW_Ur86!74g435EO8{}!B>f972vaCU|I$EEQy(~0G}lp zz9shwP1A)Anh(-m{n!%{80}H44Lq{jk-)|X11@nqmUQyip`3minw228Kk&oX(nCeu zZhC~kkp!}S(AsiijFwO|y?;{d0_cr9l|~0pl3%x$5ztm2+6vas{HTc3J8iJxmhE{B z1}pJL1gy;D=!WQ#T42_Ac@(ZT`x?ti+Js*rRm5-LbKEH4m=!~FCNMH3W-so3H|9o7 zngsY*0!t0ekty}qfY85#6RBT-!p_4qLN?5=AI<^X9~vX;#w}AvH>~h+yEL z!&2raj~K}mpXKMhbTXTt|2kV5DA|}r%Mlho`ON-#nt8b#yv(_19O+9(qvcf3J`8X$ z_j;~w5;OBdnW6JqHY5W|+yexKqy%nj*lvU*DItj@cA?IV!{5rqJxuj5&5(9jNPtZG z!94ch6iz8@SBirSx)_OWCCC8kt(O8XLn8zI@#I+CH!?D|p>J{^-qN>mU?SKyIw@H8@i)F0G<-Bnq80D9wzl@Rj<)4(ooy@Hy4t$idfHaDx3#yoceF2W z?`&Vu-qqgS-qXIaqphR8qoZSaM`y>1j;@aGj-HN{%iET>FYj2se0k^c70bJpcQ5Z* zzOu8ev%RyUb9rZH=Zem*&hE~h&Xp_LRj_r=vlF{tF5cOtD|dq zS7+CXuCA``uAZ)y-EH0N-5uS_yF0sAba!=kclUI!>}l(1@9F4S-qYE$qNl5;yQimT z@xbRJZ@;2fUwcvkSdk>^c3 zKgV+c&qX|!^IXC6i#&Zi13VjfHt}rc*~+t%=O&(C=XoE`9Xuc8`3TRwJo|VK@I1ov z8J;ijJkIlFp0DzJhbP7JdiD1@+M3?y_mehLzduQOW#2zfe0u-CMcV3P|MzCHuIgOT z)!nnQ_l@Vj$rlVb^_Q;6WNYi{8ycHtHRoo}Ice^^`3qW3b{Q5fT71f>r^Wfg8l;DCjkQVi7~W!up6Hq8p7skm)?Iz+TY9g!u(+&aMc2A3uK4d)t$X|B>n^+M zl66Parm|}j$U@bxEFe(u@tU3p;9wm+Qp`#ocqb**{m>(6}d zs%yWN{mdyp8oqJkKjhE-=95!5?0?|DJ#*FIDVK^JRs9>?w)vWY@p$Z7B*WfwxRI>IA%OD0Q-!`MhD7e6LFF-%;4vf zTI2qKi4EgJTPBCbM&pezU4#z}^o_=}kksyGZOgW6Mus-Tn+C3nCkDs1X-fOXC*$oy zlY_ArSHYI?G5XB^TgE0P1|}v{>%`E;(Z0!TbWX)as>=Df3?>)~rM3?YZ5*6LRQ7G7 zbi8e7bh4{+9fO$~7{8W*2L0Q%&=Sw$O|3lP1ZY1lA1a$RsOz|^SwhtLit zW96Ts=lysk)T_^vV;jas;w0D51d2dKE>jUiI9@dn*vT_FHYPBRPX<0cp|8p7whSa= z+9=Iqd~7o+$2h~?GB(;T+S@WdfIbrR4|s|Mt5C4|#|9=w&zxkwCpQd=OwmwmvfSr$ zP)Y_iY!WbnQi!Q4XRN9KEWY!+_pZ6^E!|tc`ELh5bN_cg^Vh%h#4oJ;@$4V};(hO0 z^?_%8b@79D?$17#`lXxZJa%*Yk}uxSc-7>u1jTPZ9W*>u^Vs-*{Leq%wJ-C%yC;8q z_v4Qb-TnP{U+~zEzVeaBo4;{Se&Ly)dGz7VM;aHeeCz(_F1!5eAO59(96NXL@89))rttn9b9X$s zyEgplEkAkbv0MLkWbJ+ba__%B_76L@ex-t52Ky%BJ`@-+MB{+Rq2rj|A|6@CQ_mxv zppj?nnqd$P*bU^H~4TwT7ZX<7w^s27I1lYGB(IV5Alu zeW4kTZbZ`_AKKhEew{I)?Sli1&YBf=!?Ik(!O?)LaSL2!{c+>Kq|*my0ncV0Zd5Sc za1QUG(J44@e>~MUKGZj=F$sjnqvZ$1pdsD5%&BtJ7^L+l7_z@kF;#G23_jW0%Mgb~ zdwU`Dbu_$fV4WY1&u#i(5d2NsRhGcJH3@vXZPo8R5bcHdq5 zzkc?6Kl0oCzrSwj&c)JfEB{qDXyby-`sU84%t?5L%?hQNm)NB9c8w0yn?71=9$kn|+!tuGR6`S|Z0 zPwf@ik6OEHq5=xOO)HR8aPaER9)J{>gWrY*LkneZ5M%eb2#@6`ebi#m48G>6JNMA}9zh zo$C Date: Thu, 26 Sep 2024 17:56:05 -0400 Subject: [PATCH 03/10] Replay and sync with reference blockchain --- unittests/savanna_misc_tests.cpp | 148 ++++++++++++++++++++++++++++++- 1 file changed, 145 insertions(+), 3 deletions(-) diff --git a/unittests/savanna_misc_tests.cpp b/unittests/savanna_misc_tests.cpp index fff7956d80..879134b3f2 100644 --- a/unittests/savanna_misc_tests.cpp +++ b/unittests/savanna_misc_tests.cpp @@ -1,4 +1,5 @@ #include "savanna_cluster.hpp" +#include using namespace eosio::chain; using namespace eosio::testing; @@ -591,18 +592,141 @@ BOOST_FIXTURE_TEST_CASE(validate_qc_requiring_finalizer_policies, savanna_cluste } FC_LOG_AND_RETHROW() +static void save_blockchain_data(const std::filesystem::path& blocks_dir, + const block_id_type& id, + const std::string& snapshot) { + auto source_log_file = blocks_dir / "blocks.log"; + auto source_index_file = blocks_dir / "blocks.index"; + + std::filesystem::path test_data_path { UNITTEST_TEST_DATA_DIR }; + auto consensus_blockchain_dir = test_data_path / "consensus_blockchain"; + auto ref_log_file = consensus_blockchain_dir / "blocks.log"; + auto ref_index_file = consensus_blockchain_dir / "blocks.index"; + auto ref_id_file_name = consensus_blockchain_dir / "id"; + auto ref_snapshot_file_name = consensus_blockchain_dir / "snapshot"; + + // save reference blocks log + std::filesystem::copy_file(source_log_file, ref_log_file, std::filesystem:: copy_options::overwrite_existing); + std::filesystem::copy_file(source_index_file, ref_index_file, std::filesystem:: copy_options::overwrite_existing); + + // save reference block_id + fc::cfile ref_id_file; + ref_id_file.set_file_path(ref_id_file_name); + ref_id_file.open("wb"); + ref_id_file.write(id.data(), id.data_size()); + ref_id_file.close(); + + // save reference snapshot + fc::cfile snapshot_file; + snapshot_file.set_file_path(ref_snapshot_file_name); + snapshot_file.open("w"); + snapshot_file.write(snapshot.data(), snapshot.size()); + snapshot_file.close(); +} + +static std::vector read_reference_file(std::string filename, const char* mode) { + std::filesystem::path test_data_path { UNITTEST_TEST_DATA_DIR }; + auto consensus_blockchain_dir = test_data_path / "consensus_blockchain"; + auto ref_file_name = consensus_blockchain_dir / filename; + + fc::cfile ref_file; + ref_file.set_file_path(ref_file_name); + ref_file.open(mode); + + ref_file.seek_end(0); + auto size = ref_file.tellp(); + + std::vector buf; + buf.resize(size); + + ref_file.seek(0); + ref_file.read(buf.data(), size); + + ref_file.close(); + + return buf; +} + +static block_id_type read_reference_id() { + std::vector buf = read_reference_file("id", "rb"); + return block_id_type(buf.data(), buf.size()); +} + +static std::string read_reference_snapshot() { + std::vector buf = read_reference_file("snapshot", "r"); + return std::string(buf.data(), buf.size()); +} + +static std::shared_ptr replay_reference_blockchain(const block_log& blog) { + // replay the reference blockchain and make sure LIB id in the replayed + // chain matches reference LIB id + // -------------------------------------------- + fc::temp_directory temp_dir; + auto config = tester::default_config(temp_dir).first; + + std::filesystem::path test_data_path { UNITTEST_TEST_DATA_DIR }; + auto ref_blockchain_dir = test_data_path / "consensus_blockchain"; + + auto genesis = eosio::chain::block_log::extract_genesis_state(ref_blockchain_dir); + BOOST_REQUIRE(genesis); + + std::filesystem::create_directories(config.blocks_dir); + + std::filesystem::copy(ref_blockchain_dir / "blocks.log", config.blocks_dir / "blocks.log"); + std::filesystem::copy(ref_blockchain_dir / "blocks.index", config.blocks_dir / "blocks.index"); + + // do a full block invariants check + config.force_all_checks = true; + + // replay the reference blockchain + std::shared_ptr replay_chain = std::make_shared(config, *genesis); + + auto ref_lib_id = blog.head_id(); + BOOST_REQUIRE_EQUAL(*ref_lib_id, replay_chain->last_irreversible_block_id()); + + return replay_chain; +} + +static void sync_replayed_blockchain(const std::shared_ptr& replay_chain, const block_log& blog) { + tester sync_chain; + std::filesystem::remove_all(sync_chain.get_config().state_dir); + std::filesystem::remove_all(sync_chain.get_config().blocks_dir); + sync_chain.close(); + + // start from reference snapshot + sync_chain.open(buffered_snapshot_suite::get_reader(read_reference_snapshot())); + + // Sync with the replayed blockchain + while( sync_chain.fork_db_head().block_num() < replay_chain->fork_db_head().block_num() ) { + auto fb = replay_chain->fetch_block_by_number( sync_chain.fork_db_head().block_num()+1 ); + sync_chain.push_block( fb ); + } + + // In syncing, use the head for checking as it advances further than LIB + auto head_block_num = sync_chain.head().block_num(); + signed_block_ptr ref_block = blog.read_block_by_num(head_block_num); + + BOOST_REQUIRE_EQUAL(ref_block->calculate_id(), sync_chain.head().id()); +} // ---------------------------------------------------------------------------------------------------- // For issue #694, we need to change the finality core of the `block_header_state`, but we want to // ensure that this doesn't create a consensus incompatibility with Spring 1.0.0, so the blocks created // with newer versions remain compatible (and linkable) by Spring 1.0.0. // ---------------------------------------------------------------------------------------------------- -BOOST_FIXTURE_TEST_CASE(verify_spring_1_0_block_compatibitity, savanna_cluster::cluster_t) try { +BOOST_FIXTURE_TEST_CASE(verify_block_compatibitity, savanna_cluster::cluster_t) try { using namespace savanna_cluster; auto& A=_nodes[0]; const auto& tester_account = "tester"_n; //_debug_mode = true; + bool save_blockchain = tester::arguments_contains("--save-blockchain"); + + std::string snapshot; + if (save_blockchain) { // take a snapshot at the beginning + snapshot = A.snapshot(); + } + // update finalizer_policy with a new key for B // -------------------------------------------- base_tester::finalizer_policy_input input; @@ -681,10 +805,28 @@ BOOST_FIXTURE_TEST_CASE(verify_spring_1_0_block_compatibitity, savanna_cluster:: BOOST_REQUIRE_EQUAL(qc_s(qc(b9)), strong_qc(b8)); // b9 claims a strong QC on b8 BOOST_REQUIRE_EQUAL(A.lib_number, b6->block_num()); // b9 makes B6 final - // check that the block id of b9 match what we got with Spring 1.0.0 + // check that the block id of b9 match what we got before. auto b9_id = b9->calculate_id(); - BOOST_REQUIRE_EQUAL(b9_id, block_id_type{"00000013725f3d79bd4dd4091d0853d010a320f95240981711a942673ad87918"}); + BOOST_REQUIRE_EQUAL(b9_id, read_reference_id()); + + if (save_blockchain) { + save_blockchain_data(A.get_config().blocks_dir, b9_id, snapshot); + return; + } + + std::filesystem::path test_data_path { UNITTEST_TEST_DATA_DIR }; + auto ref_blockchain_dir = test_data_path / "consensus_blockchain"; + block_log blog(ref_blockchain_dir); + + // replay the reference blockchain and make sure LIB id in the replayed + // chain matches reference LIB id + // -------------------------------------------- + std::shared_ptr replay_chain = replay_reference_blockchain(blog); + // start another blockchain using snapshot, and sync with the blocks + // in the replayed blockchain as source + // ----------------------------------------------- + sync_replayed_blockchain(replay_chain, blog); } FC_LOG_AND_RETHROW() /* ----------------------------------------------------------------------------------------------------- From 69e94d34d5610ac219217d9de254b0423007c31b Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Fri, 27 Sep 2024 09:59:14 -0400 Subject: [PATCH 04/10] fix temp_dir going out of scope --- unittests/savanna_misc_tests.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/unittests/savanna_misc_tests.cpp b/unittests/savanna_misc_tests.cpp index 879134b3f2..c13afe2fae 100644 --- a/unittests/savanna_misc_tests.cpp +++ b/unittests/savanna_misc_tests.cpp @@ -657,11 +657,11 @@ static std::string read_reference_snapshot() { return std::string(buf.data(), buf.size()); } -static std::shared_ptr replay_reference_blockchain(const block_log& blog) { +// need to pass in temp_dir. otherwise it will be destroyed after replay_reference_blockchain returns +static std::unique_ptr replay_reference_blockchain(const fc::temp_directory& temp_dir, const block_log& blog) { // replay the reference blockchain and make sure LIB id in the replayed // chain matches reference LIB id // -------------------------------------------- - fc::temp_directory temp_dir; auto config = tester::default_config(temp_dir).first; std::filesystem::path test_data_path { UNITTEST_TEST_DATA_DIR }; @@ -679,7 +679,7 @@ static std::shared_ptr replay_reference_blockchain(const block_log& blog config.force_all_checks = true; // replay the reference blockchain - std::shared_ptr replay_chain = std::make_shared(config, *genesis); + std::unique_ptr replay_chain = std::make_unique(config, *genesis); auto ref_lib_id = blog.head_id(); BOOST_REQUIRE_EQUAL(*ref_lib_id, replay_chain->last_irreversible_block_id()); @@ -687,16 +687,18 @@ static std::shared_ptr replay_reference_blockchain(const block_log& blog return replay_chain; } -static void sync_replayed_blockchain(const std::shared_ptr& replay_chain, const block_log& blog) { +static void sync_replayed_blockchain(std::unique_ptr&& replay_chain, const block_log& blog) { tester sync_chain; + sync_chain.close(); // stop the chain + + // remove state and blocks log so we can restart from snapshot std::filesystem::remove_all(sync_chain.get_config().state_dir); std::filesystem::remove_all(sync_chain.get_config().blocks_dir); - sync_chain.close(); - // start from reference snapshot + // restart from reference snapshot sync_chain.open(buffered_snapshot_suite::get_reader(read_reference_snapshot())); - // Sync with the replayed blockchain + // sync with the replayed blockchain while( sync_chain.fork_db_head().block_num() < replay_chain->fork_db_head().block_num() ) { auto fb = replay_chain->fetch_block_by_number( sync_chain.fork_db_head().block_num()+1 ); sync_chain.push_block( fb ); @@ -821,12 +823,13 @@ BOOST_FIXTURE_TEST_CASE(verify_block_compatibitity, savanna_cluster::cluster_t) // replay the reference blockchain and make sure LIB id in the replayed // chain matches reference LIB id // -------------------------------------------- - std::shared_ptr replay_chain = replay_reference_blockchain(blog); + fc::temp_directory temp_dir; // need to pass in temp_dir. otherwise it would be destroyed after replay_reference_blockchain returns + std::unique_ptr replay_chain = replay_reference_blockchain(temp_dir, blog); // start another blockchain using snapshot, and sync with the blocks // in the replayed blockchain as source // ----------------------------------------------- - sync_replayed_blockchain(replay_chain, blog); + sync_replayed_blockchain(std::move(replay_chain), blog); } FC_LOG_AND_RETHROW() /* ----------------------------------------------------------------------------------------------------- From a984c91e82a799f893344aa4cf43fdae2c5a3459 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Fri, 27 Sep 2024 10:53:51 -0400 Subject: [PATCH 05/10] Use fc::read_file_contents to read snapshot and reference ID files (which are small) --- unittests/savanna_misc_tests.cpp | 41 +++++++++++--------------------- 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/unittests/savanna_misc_tests.cpp b/unittests/savanna_misc_tests.cpp index c13afe2fae..3896b7fc0c 100644 --- a/unittests/savanna_misc_tests.cpp +++ b/unittests/savanna_misc_tests.cpp @@ -1,6 +1,8 @@ -#include "savanna_cluster.hpp" +#include #include +#include // for read_file_contents + using namespace eosio::chain; using namespace eosio::testing; @@ -624,37 +626,22 @@ static void save_blockchain_data(const std::filesystem::path& blocks_dir, snapshot_file.close(); } -static std::vector read_reference_file(std::string filename, const char* mode) { +static block_id_type read_reference_id() { std::filesystem::path test_data_path { UNITTEST_TEST_DATA_DIR }; - auto consensus_blockchain_dir = test_data_path / "consensus_blockchain"; - auto ref_file_name = consensus_blockchain_dir / filename; - - fc::cfile ref_file; - ref_file.set_file_path(ref_file_name); - ref_file.open(mode); - - ref_file.seek_end(0); - auto size = ref_file.tellp(); - - std::vector buf; - buf.resize(size); - - ref_file.seek(0); - ref_file.read(buf.data(), size); + auto ref_id_file_path = test_data_path / "consensus_blockchain/id"; + std::string content; + fc::read_file_contents(ref_id_file_path, content); - ref_file.close(); - - return buf; -} - -static block_id_type read_reference_id() { - std::vector buf = read_reference_file("id", "rb"); - return block_id_type(buf.data(), buf.size()); + return block_id_type(content.data(), content.size()); } static std::string read_reference_snapshot() { - std::vector buf = read_reference_file("snapshot", "r"); - return std::string(buf.data(), buf.size()); + std::filesystem::path test_data_path { UNITTEST_TEST_DATA_DIR }; + auto ref_id_file_path = test_data_path / "consensus_blockchain/snapshot"; + std::string content; + fc::read_file_contents(ref_id_file_path, content); + + return content; } // need to pass in temp_dir. otherwise it will be destroyed after replay_reference_blockchain returns From faed7da3157c3605fa8790699a2a74387fab4419 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Fri, 27 Sep 2024 11:52:34 -0400 Subject: [PATCH 06/10] Calculate ref_blockchain_path in only one place --- unittests/savanna_misc_tests.cpp | 63 ++++++++++++++++---------------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/unittests/savanna_misc_tests.cpp b/unittests/savanna_misc_tests.cpp index 3896b7fc0c..4e57d5755f 100644 --- a/unittests/savanna_misc_tests.cpp +++ b/unittests/savanna_misc_tests.cpp @@ -594,18 +594,17 @@ BOOST_FIXTURE_TEST_CASE(validate_qc_requiring_finalizer_policies, savanna_cluste } FC_LOG_AND_RETHROW() -static void save_blockchain_data(const std::filesystem::path& blocks_dir, +static void save_blockchain_data(const std::filesystem::path& ref_blockchain_path, + const std::filesystem::path& blocks_path, const block_id_type& id, const std::string& snapshot) { - auto source_log_file = blocks_dir / "blocks.log"; - auto source_index_file = blocks_dir / "blocks.index"; + auto source_log_file = blocks_path / "blocks.log"; + auto source_index_file = blocks_path / "blocks.index"; - std::filesystem::path test_data_path { UNITTEST_TEST_DATA_DIR }; - auto consensus_blockchain_dir = test_data_path / "consensus_blockchain"; - auto ref_log_file = consensus_blockchain_dir / "blocks.log"; - auto ref_index_file = consensus_blockchain_dir / "blocks.index"; - auto ref_id_file_name = consensus_blockchain_dir / "id"; - auto ref_snapshot_file_name = consensus_blockchain_dir / "snapshot"; + auto ref_log_file = ref_blockchain_path / "blocks.log"; + auto ref_index_file = ref_blockchain_path / "blocks.index"; + auto ref_id_file_name = ref_blockchain_path / "id"; + auto ref_snapshot_file_name = ref_blockchain_path / "snapshot"; // save reference blocks log std::filesystem::copy_file(source_log_file, ref_log_file, std::filesystem:: copy_options::overwrite_existing); @@ -626,41 +625,38 @@ static void save_blockchain_data(const std::filesystem::path& blocks_dir, snapshot_file.close(); } -static block_id_type read_reference_id() { - std::filesystem::path test_data_path { UNITTEST_TEST_DATA_DIR }; - auto ref_id_file_path = test_data_path / "consensus_blockchain/id"; +static block_id_type read_reference_id(const std::filesystem::path& ref_blockchain_path) { + auto ref_id_file_path = ref_blockchain_path / "id"; std::string content; fc::read_file_contents(ref_id_file_path, content); return block_id_type(content.data(), content.size()); } -static std::string read_reference_snapshot() { - std::filesystem::path test_data_path { UNITTEST_TEST_DATA_DIR }; - auto ref_id_file_path = test_data_path / "consensus_blockchain/snapshot"; +static std::string read_reference_snapshot(const std::filesystem::path& ref_blockchain_path) { + auto ref_snapshot_file_path = ref_blockchain_path / "snapshot"; std::string content; - fc::read_file_contents(ref_id_file_path, content); + fc::read_file_contents(ref_snapshot_file_path, content); return content; } // need to pass in temp_dir. otherwise it will be destroyed after replay_reference_blockchain returns -static std::unique_ptr replay_reference_blockchain(const fc::temp_directory& temp_dir, const block_log& blog) { +static std::unique_ptr replay_reference_blockchain(const std::filesystem::path& ref_blockchain_path, + const fc::temp_directory& temp_dir, + const block_log& blog) { // replay the reference blockchain and make sure LIB id in the replayed // chain matches reference LIB id // -------------------------------------------- auto config = tester::default_config(temp_dir).first; - std::filesystem::path test_data_path { UNITTEST_TEST_DATA_DIR }; - auto ref_blockchain_dir = test_data_path / "consensus_blockchain"; - - auto genesis = eosio::chain::block_log::extract_genesis_state(ref_blockchain_dir); + auto genesis = eosio::chain::block_log::extract_genesis_state(ref_blockchain_path); BOOST_REQUIRE(genesis); std::filesystem::create_directories(config.blocks_dir); - std::filesystem::copy(ref_blockchain_dir / "blocks.log", config.blocks_dir / "blocks.log"); - std::filesystem::copy(ref_blockchain_dir / "blocks.index", config.blocks_dir / "blocks.index"); + std::filesystem::copy(ref_blockchain_path / "blocks.log", config.blocks_dir / "blocks.log"); + std::filesystem::copy(ref_blockchain_path / "blocks.index", config.blocks_dir / "blocks.index"); // do a full block invariants check config.force_all_checks = true; @@ -674,7 +670,9 @@ static std::unique_ptr replay_reference_blockchain(const fc::temp_direct return replay_chain; } -static void sync_replayed_blockchain(std::unique_ptr&& replay_chain, const block_log& blog) { +static void sync_replayed_blockchain(const std::filesystem::path& ref_blockchain_path, + std::unique_ptr&& replay_chain, + const block_log& blog) { tester sync_chain; sync_chain.close(); // stop the chain @@ -683,7 +681,7 @@ static void sync_replayed_blockchain(std::unique_ptr&& replay_chain, con std::filesystem::remove_all(sync_chain.get_config().blocks_dir); // restart from reference snapshot - sync_chain.open(buffered_snapshot_suite::get_reader(read_reference_snapshot())); + sync_chain.open(buffered_snapshot_suite::get_reader(read_reference_snapshot(ref_blockchain_path))); // sync with the replayed blockchain while( sync_chain.fork_db_head().block_num() < replay_chain->fork_db_head().block_num() ) { @@ -794,29 +792,30 @@ BOOST_FIXTURE_TEST_CASE(verify_block_compatibitity, savanna_cluster::cluster_t) BOOST_REQUIRE_EQUAL(qc_s(qc(b9)), strong_qc(b8)); // b9 claims a strong QC on b8 BOOST_REQUIRE_EQUAL(A.lib_number, b6->block_num()); // b9 makes B6 final + std::filesystem::path test_data_path { UNITTEST_TEST_DATA_DIR }; + auto ref_blockchain_path = test_data_path / "consensus_blockchain"; + // check that the block id of b9 match what we got before. auto b9_id = b9->calculate_id(); - BOOST_REQUIRE_EQUAL(b9_id, read_reference_id()); + BOOST_REQUIRE_EQUAL(b9_id, read_reference_id(ref_blockchain_path)); if (save_blockchain) { - save_blockchain_data(A.get_config().blocks_dir, b9_id, snapshot); + save_blockchain_data(ref_blockchain_path, A.get_config().blocks_dir, b9_id, snapshot); return; } - std::filesystem::path test_data_path { UNITTEST_TEST_DATA_DIR }; - auto ref_blockchain_dir = test_data_path / "consensus_blockchain"; - block_log blog(ref_blockchain_dir); + block_log blog(ref_blockchain_path); // replay the reference blockchain and make sure LIB id in the replayed // chain matches reference LIB id // -------------------------------------------- fc::temp_directory temp_dir; // need to pass in temp_dir. otherwise it would be destroyed after replay_reference_blockchain returns - std::unique_ptr replay_chain = replay_reference_blockchain(temp_dir, blog); + std::unique_ptr replay_chain = replay_reference_blockchain(ref_blockchain_path, temp_dir, blog); // start another blockchain using snapshot, and sync with the blocks // in the replayed blockchain as source // ----------------------------------------------- - sync_replayed_blockchain(std::move(replay_chain), blog); + sync_replayed_blockchain(ref_blockchain_path, std::move(replay_chain), blog); } FC_LOG_AND_RETHROW() /* ----------------------------------------------------------------------------------------------------- From 43f19bb1a57667a7ce6a622b303c94e805fa1f8a Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Fri, 27 Sep 2024 15:20:28 -0400 Subject: [PATCH 07/10] Add more comments --- unittests/savanna_misc_tests.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/unittests/savanna_misc_tests.cpp b/unittests/savanna_misc_tests.cpp index 4e57d5755f..51f728489d 100644 --- a/unittests/savanna_misc_tests.cpp +++ b/unittests/savanna_misc_tests.cpp @@ -647,7 +647,7 @@ static std::unique_ptr replay_reference_blockchain(const std::filesystem const block_log& blog) { // replay the reference blockchain and make sure LIB id in the replayed // chain matches reference LIB id - // -------------------------------------------- + // -------------------------------------------------------------------- auto config = tester::default_config(temp_dir).first; auto genesis = eosio::chain::block_log::extract_genesis_state(ref_blockchain_path); @@ -699,7 +699,14 @@ static void sync_replayed_blockchain(const std::filesystem::path& ref_blockchain // ---------------------------------------------------------------------------------------------------- // For issue #694, we need to change the finality core of the `block_header_state`, but we want to // ensure that this doesn't create a consensus incompatibility with Spring 1.0.0, so the blocks created -// with newer versions remain compatible (and linkable) by Spring 1.0.0. +// with newer versions remain compatible (and linkable) with blocks by Spring 1.0.0. +// +// This test adds a utility that saves reference blockchain data and checks for +// regression in compatibility of syncing and replaying the reference blockchain data. +// +// To save reference blockchain data in `unittests/test-data/consensus_blockchain`, +// run +// `unittests/unit_test -t savanna_misc_tests/verify_block_compatibitity -- --save-blockchain` // ---------------------------------------------------------------------------------------------------- BOOST_FIXTURE_TEST_CASE(verify_block_compatibitity, savanna_cluster::cluster_t) try { using namespace savanna_cluster; @@ -808,13 +815,13 @@ BOOST_FIXTURE_TEST_CASE(verify_block_compatibitity, savanna_cluster::cluster_t) // replay the reference blockchain and make sure LIB id in the replayed // chain matches reference LIB id - // -------------------------------------------- + // -------------------------------------------------------------------- fc::temp_directory temp_dir; // need to pass in temp_dir. otherwise it would be destroyed after replay_reference_blockchain returns std::unique_ptr replay_chain = replay_reference_blockchain(ref_blockchain_path, temp_dir, blog); - // start another blockchain using snapshot, and sync with the blocks - // in the replayed blockchain as source - // ----------------------------------------------- + // start another blockchain using reference snapshot, and sync with the blocks + // from the replayed blockchain + // --------------------------------------------------------------------------- sync_replayed_blockchain(ref_blockchain_path, std::move(replay_chain), blog); } FC_LOG_AND_RETHROW() From 351f9b422912b49547addf303a567a8e6f964328 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Mon, 30 Sep 2024 16:17:16 -0400 Subject: [PATCH 08/10] Use const std::string& for the argument of arguments_contains() --- libraries/testing/include/eosio/testing/tester.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/testing/include/eosio/testing/tester.hpp b/libraries/testing/include/eosio/testing/tester.hpp index 86dd17e6f4..4fd281c2cd 100644 --- a/libraries/testing/include/eosio/testing/tester.hpp +++ b/libraries/testing/include/eosio/testing/tester.hpp @@ -521,7 +521,7 @@ namespace eosio::testing { return {cfg, gen}; } - static bool arguments_contains(std::string arg) { + static bool arguments_contains(const std::string& arg) { auto argc = boost::unit_test::framework::master_test_suite().argc; auto argv = boost::unit_test::framework::master_test_suite().argv; From 2fd7c000592ab644c7a21c51d008ac3303e183e1 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Mon, 30 Sep 2024 16:18:04 -0400 Subject: [PATCH 09/10] Remove spaces between std::filesystem:: and copy_options::overwrite_existing --- unittests/savanna_misc_tests.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/unittests/savanna_misc_tests.cpp b/unittests/savanna_misc_tests.cpp index 51f728489d..7492734696 100644 --- a/unittests/savanna_misc_tests.cpp +++ b/unittests/savanna_misc_tests.cpp @@ -607,8 +607,8 @@ static void save_blockchain_data(const std::filesystem::path& ref_blockchain_pat auto ref_snapshot_file_name = ref_blockchain_path / "snapshot"; // save reference blocks log - std::filesystem::copy_file(source_log_file, ref_log_file, std::filesystem:: copy_options::overwrite_existing); - std::filesystem::copy_file(source_index_file, ref_index_file, std::filesystem:: copy_options::overwrite_existing); + std::filesystem::copy_file(source_log_file, ref_log_file, std::filesystem::copy_options::overwrite_existing); + std::filesystem::copy_file(source_index_file, ref_index_file, std::filesystem::copy_options::overwrite_existing); // save reference block_id fc::cfile ref_id_file; From f0b93a969fda1a499423d0a74015113980114670 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Tue, 1 Oct 2024 15:54:35 -0400 Subject: [PATCH 10/10] Save blockchain data before validating block id (otherwise it won't be saved if it needs to be changed in the future --- unittests/savanna_misc_tests.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/unittests/savanna_misc_tests.cpp b/unittests/savanna_misc_tests.cpp index 7492734696..451aed5e81 100644 --- a/unittests/savanna_misc_tests.cpp +++ b/unittests/savanna_misc_tests.cpp @@ -804,13 +804,15 @@ BOOST_FIXTURE_TEST_CASE(verify_block_compatibitity, savanna_cluster::cluster_t) // check that the block id of b9 match what we got before. auto b9_id = b9->calculate_id(); - BOOST_REQUIRE_EQUAL(b9_id, read_reference_id(ref_blockchain_path)); if (save_blockchain) { save_blockchain_data(ref_blockchain_path, A.get_config().blocks_dir, b9_id, snapshot); return; } + // Do block id validation after we save blockchain data in case the id needs to be changed in future + BOOST_REQUIRE_EQUAL(b9_id, read_reference_id(ref_blockchain_path)); + block_log blog(ref_blockchain_path); // replay the reference blockchain and make sure LIB id in the replayed